diff --git a/vendor/github.com/weaveworks/common/exec/exec.go b/vendor/github.com/weaveworks/common/exec/exec.go index fc0b27ad1..c4b7721a0 100644 --- a/vendor/github.com/weaveworks/common/exec/exec.go +++ b/vendor/github.com/weaveworks/common/exec/exec.go @@ -14,6 +14,7 @@ type Cmd interface { Kill() error Output() ([]byte, error) Run() error + SetEnv([]string) } // Command is a hook for mocking @@ -28,3 +29,7 @@ type realCmd struct { func (c *realCmd) Kill() error { return c.Cmd.Process.Kill() } + +func (c *realCmd) SetEnv(env []string) { + c.Cmd.Env = env +} diff --git a/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.go b/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.go new file mode 100644 index 000000000..a59a6eba1 --- /dev/null +++ b/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.go @@ -0,0 +1,170 @@ +package httpgrpc + +import ( + "bytes" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/http/httptest" + "strings" + "sync" + "time" + + "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" + "github.com/mwitkow/go-grpc-middleware" + "github.com/opentracing/opentracing-go" + "github.com/sercand/kuberesolver" + "golang.org/x/net/context" + "google.golang.org/grpc" + + "github.com/weaveworks/common/middleware" +) + +const dialTimeout = 5 * time.Second + +// Server implements HTTPServer. HTTPServer is a generated interface that gRPC +// servers must implement. +type Server struct { + handler http.Handler +} + +// NewServer makes a new Server. +func NewServer(handler http.Handler) *Server { + return &Server{ + handler: handler, + } +} + +// Handle implements HTTPServer. +func (s Server) Handle(ctx context.Context, r *HTTPRequest) (*HTTPResponse, error) { + req, err := http.NewRequest(r.Method, r.Url, ioutil.NopCloser(bytes.NewReader(r.Body))) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + toHeader(r.Headers, req.Header) + req.RequestURI = r.Url + recorder := httptest.NewRecorder() + s.handler.ServeHTTP(recorder, req) + resp := &HTTPResponse{ + Code: int32(recorder.Code), + Headers: fromHeader(recorder.Header()), + Body: recorder.Body.Bytes(), + } + return resp, nil +} + +// Client is a http.Handler that forwards the request over gRPC. +type Client struct { + mtx sync.RWMutex + service string + namespace string + port string + client HTTPClient + conn *grpc.ClientConn +} + +// NewClient makes a new Client, given a kubernetes service address. Expects +// an address of the form .: +func NewClient(address string) (*Client, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + parts := strings.SplitN(host, ".", 2) + service, namespace := parts[0], "default" + if len(parts) == 2 { + namespace = parts[1] + } + return &Client{ + service: service, + namespace: namespace, + port: port, + }, nil +} + +func (c *Client) connect(ctx context.Context) error { + c.mtx.RLock() + connected := c.conn != nil + c.mtx.RUnlock() + if connected { + return nil + } + + c.mtx.Lock() + defer c.mtx.Unlock() + if c.conn != nil { + return nil + } + + balancer := kuberesolver.NewWithNamespace(c.namespace) + ctxDeadline, cancel := context.WithTimeout(ctx, dialTimeout) + defer cancel() + conn, err := grpc.DialContext( + ctxDeadline, + fmt.Sprintf("kubernetes://%s:%s", c.service, c.port), + balancer.DialOption(), + grpc.WithInsecure(), + grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient( + otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer()), + middleware.ClientUserHeaderInterceptor, + )), + ) + if err != nil { + return err + } + c.client = NewHTTPClient(conn) + c.conn = conn + return nil +} + +// ServeHTTP implements http.Handler +func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if err := c.connect(r.Context()); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + req := &HTTPRequest{ + Method: r.Method, + Url: r.RequestURI, + Body: body, + Headers: fromHeader(r.Header), + } + + resp, err := c.client.Handle(r.Context(), req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + toHeader(resp.Headers, w.Header()) + w.WriteHeader(int(resp.Code)) + if _, err := w.Write(resp.Body); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +func toHeader(hs []*Header, header http.Header) { + for _, h := range hs { + header[h.Key] = h.Values + } +} + +func fromHeader(hs http.Header) []*Header { + result := make([]*Header, 0, len(hs)) + for k, vs := range hs { + result = append(result, &Header{ + Key: k, + Values: vs, + }) + } + return result +} diff --git a/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.pb.go b/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.pb.go new file mode 100644 index 000000000..02b2a4786 --- /dev/null +++ b/vendor/github.com/weaveworks/common/httpgrpc/httpgrpc.pb.go @@ -0,0 +1,231 @@ +// Code generated by protoc-gen-go. +// source: httpgrpc.proto +// DO NOT EDIT! + +/* +Package httpgrpc is a generated protocol buffer package. + +It is generated from these files: + httpgrpc.proto + +It has these top-level messages: + HTTPRequest + HTTPResponse + Header +*/ +package httpgrpc + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type HTTPRequest struct { + Method string `protobuf:"bytes,1,opt,name=method" json:"method,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"` + Headers []*Header `protobuf:"bytes,3,rep,name=headers" json:"headers,omitempty"` + Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` +} + +func (m *HTTPRequest) Reset() { *m = HTTPRequest{} } +func (m *HTTPRequest) String() string { return proto.CompactTextString(m) } +func (*HTTPRequest) ProtoMessage() {} +func (*HTTPRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *HTTPRequest) GetMethod() string { + if m != nil { + return m.Method + } + return "" +} + +func (m *HTTPRequest) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *HTTPRequest) GetHeaders() []*Header { + if m != nil { + return m.Headers + } + return nil +} + +func (m *HTTPRequest) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +type HTTPResponse struct { + Code int32 `protobuf:"varint,1,opt,name=Code" json:"Code,omitempty"` + Headers []*Header `protobuf:"bytes,2,rep,name=headers" json:"headers,omitempty"` + Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` +} + +func (m *HTTPResponse) Reset() { *m = HTTPResponse{} } +func (m *HTTPResponse) String() string { return proto.CompactTextString(m) } +func (*HTTPResponse) ProtoMessage() {} +func (*HTTPResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *HTTPResponse) GetCode() int32 { + if m != nil { + return m.Code + } + return 0 +} + +func (m *HTTPResponse) GetHeaders() []*Header { + if m != nil { + return m.Headers + } + return nil +} + +func (m *HTTPResponse) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +type Header struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Values []string `protobuf:"bytes,2,rep,name=values" json:"values,omitempty"` +} + +func (m *Header) Reset() { *m = Header{} } +func (m *Header) String() string { return proto.CompactTextString(m) } +func (*Header) ProtoMessage() {} +func (*Header) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Header) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *Header) GetValues() []string { + if m != nil { + return m.Values + } + return nil +} + +func init() { + proto.RegisterType((*HTTPRequest)(nil), "httpgrpc.HTTPRequest") + proto.RegisterType((*HTTPResponse)(nil), "httpgrpc.HTTPResponse") + proto.RegisterType((*Header)(nil), "httpgrpc.Header") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for HTTP service + +type HTTPClient interface { + Handle(ctx context.Context, in *HTTPRequest, opts ...grpc.CallOption) (*HTTPResponse, error) +} + +type hTTPClient struct { + cc *grpc.ClientConn +} + +func NewHTTPClient(cc *grpc.ClientConn) HTTPClient { + return &hTTPClient{cc} +} + +func (c *hTTPClient) Handle(ctx context.Context, in *HTTPRequest, opts ...grpc.CallOption) (*HTTPResponse, error) { + out := new(HTTPResponse) + err := grpc.Invoke(ctx, "/httpgrpc.HTTP/Handle", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for HTTP service + +type HTTPServer interface { + Handle(context.Context, *HTTPRequest) (*HTTPResponse, error) +} + +func RegisterHTTPServer(s *grpc.Server, srv HTTPServer) { + s.RegisterService(&_HTTP_serviceDesc, srv) +} + +func _HTTP_Handle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HTTPRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HTTPServer).Handle(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/httpgrpc.HTTP/Handle", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HTTPServer).Handle(ctx, req.(*HTTPRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _HTTP_serviceDesc = grpc.ServiceDesc{ + ServiceName: "httpgrpc.HTTP", + HandlerType: (*HTTPServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Handle", + Handler: _HTTP_Handle_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "httpgrpc.proto", +} + +func init() { proto.RegisterFile("httpgrpc.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 231 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x90, 0x31, 0x4f, 0xc3, 0x30, + 0x10, 0x85, 0x49, 0x1d, 0x0c, 0xbd, 0x56, 0xa8, 0x3a, 0x89, 0xca, 0x62, 0x8a, 0x32, 0x45, 0x0c, + 0x1d, 0xc2, 0xc4, 0x88, 0x58, 0x32, 0x22, 0xab, 0x7f, 0x20, 0xc1, 0x27, 0x22, 0x11, 0x6a, 0x63, + 0x3b, 0xa0, 0xfe, 0x7b, 0x64, 0x3b, 0x85, 0x88, 0xa9, 0xdb, 0x7b, 0xe7, 0x27, 0x7f, 0xf7, 0x0e, + 0x6e, 0x7a, 0xef, 0xcd, 0x9b, 0x35, 0xaf, 0x3b, 0x63, 0xb5, 0xd7, 0x78, 0x7d, 0xf2, 0xe5, 0x37, + 0xac, 0x9a, 0xfd, 0xfe, 0x45, 0xd2, 0xe7, 0x48, 0xce, 0xe3, 0x16, 0xf8, 0x07, 0xf9, 0x5e, 0x2b, + 0x91, 0x15, 0x59, 0xb5, 0x94, 0x93, 0xc3, 0x0d, 0xb0, 0xd1, 0x0e, 0x62, 0x11, 0x87, 0x41, 0xe2, + 0x3d, 0x5c, 0xf5, 0xd4, 0x2a, 0xb2, 0x4e, 0xb0, 0x82, 0x55, 0xab, 0x7a, 0xb3, 0xfb, 0x85, 0x34, + 0xf1, 0x41, 0x9e, 0x02, 0x88, 0x90, 0x77, 0x5a, 0x1d, 0x45, 0x5e, 0x64, 0xd5, 0x5a, 0x46, 0x5d, + 0x76, 0xb0, 0x4e, 0x60, 0x67, 0xf4, 0xc1, 0x51, 0xc8, 0x3c, 0x6b, 0x45, 0x91, 0x7b, 0x29, 0xa3, + 0x9e, 0x33, 0x16, 0xe7, 0x32, 0xd8, 0x8c, 0x51, 0x03, 0x4f, 0xb1, 0xb0, 0xff, 0x3b, 0x1d, 0xa7, + 0x52, 0x41, 0x86, 0xa6, 0x5f, 0xed, 0x30, 0x52, 0xfa, 0x7a, 0x29, 0x27, 0x57, 0x3f, 0x41, 0x1e, + 0xf6, 0xc2, 0x47, 0xe0, 0x4d, 0x7b, 0x50, 0x03, 0xe1, 0xed, 0x0c, 0xfa, 0x77, 0xaa, 0xbb, 0xed, + 0xff, 0x71, 0x2a, 0x52, 0x5e, 0x74, 0x3c, 0x1e, 0xf9, 0xe1, 0x27, 0x00, 0x00, 0xff, 0xff, 0x47, + 0x4e, 0x55, 0x95, 0x76, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/weaveworks/common/instrument/instrument.go b/vendor/github.com/weaveworks/common/instrument/instrument.go index d90aa90d3..6afb72b19 100644 --- a/vendor/github.com/weaveworks/common/instrument/instrument.go +++ b/vendor/github.com/weaveworks/common/instrument/instrument.go @@ -48,6 +48,8 @@ func TimeRequestHistogramStatus(ctx context.Context, method string, metric *prom ext.Error.Set(sp, true) } sp.Finish() - metric.WithLabelValues(method, toStatusCode(err)).Observe(time.Now().Sub(startTime).Seconds()) + if metric != nil { + metric.WithLabelValues(method, toStatusCode(err)).Observe(time.Now().Sub(startTime).Seconds()) + } return err } diff --git a/vendor/github.com/weaveworks/common/mflag/flag.go b/vendor/github.com/weaveworks/common/mflag/flag.go new file mode 100644 index 000000000..22b9111da --- /dev/null +++ b/vendor/github.com/weaveworks/common/mflag/flag.go @@ -0,0 +1,1267 @@ +// Copyright 2014-2016 The Docker & Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package mflag implements command-line flag parsing. +// +// Usage: +// +// Define flags using flag.String(), Bool(), Int(), etc. +// +// This declares an integer flag, -f or --flagname, stored in the pointer ip, with type *int. +// import flag "github.com/docker/docker/pkg/mflag" +// var ip = flag.Int([]string{"f", "-flagname"}, 1234, "help message for flagname") +// If you like, you can bind the flag to a variable using the Var() functions. +// var flagvar int +// func init() { +// // -flaghidden will work, but will be hidden from the usage +// flag.IntVar(&flagvar, []string{"f", "#flaghidden", "-flagname"}, 1234, "help message for flagname") +// } +// Or you can create custom flags that satisfy the Value interface (with +// pointer receivers) and couple them to flag parsing by +// flag.Var(&flagVal, []string{"name"}, "help message for flagname") +// For such flags, the default value is just the initial value of the variable. +// +// You can also add "deprecated" flags, they are still usable, but are not shown +// in the usage and will display a warning when you try to use them. `#` before +// an option means this option is deprecated, if there is a following option +// without `#` ahead, then that's the replacement, if not, it will just be removed: +// var ip = flag.Int([]string{"#f", "#flagname", "-flagname"}, 1234, "help message for flagname") +// this will display: `Warning: '-f' is deprecated, it will be replaced by '--flagname' soon. See usage.` or +// this will display: `Warning: '-flagname' is deprecated, it will be replaced by '--flagname' soon. See usage.` +// var ip = flag.Int([]string{"f", "#flagname"}, 1234, "help message for flagname") +// will display: `Warning: '-flagname' is deprecated, it will be removed soon. See usage.` +// so you can only use `-f`. +// +// You can also group one letter flags, if you declare +// var v = flag.Bool([]string{"v", "-verbose"}, false, "help message for verbose") +// var s = flag.Bool([]string{"s", "-slow"}, false, "help message for slow") +// you will be able to use the -vs or -sv +// +// After all flags are defined, call +// flag.Parse() +// to parse the command line into the defined flags. +// +// Flags may then be used directly. If you're using the flags themselves, +// they are all pointers; if you bind to variables, they're values. +// fmt.Println("ip has value ", *ip) +// fmt.Println("flagvar has value ", flagvar) +// +// After parsing, the arguments after the flag are available as the +// slice flag.Args() or individually as flag.Arg(i). +// The arguments are indexed from 0 through flag.NArg()-1. +// +// Command line flag syntax: +// -flag +// -flag=x +// -flag="x" +// -flag='x' +// -flag x // non-boolean flags only +// One or two minus signs may be used; they are equivalent. +// The last form is not permitted for boolean flags because the +// meaning of the command +// cmd -x * +// will change if there is a file called 0, false, etc. You must +// use the -flag=false form to turn off a boolean flag. +// +// Flag parsing stops just before the first non-flag argument +// ("-" is a non-flag argument) or after the terminator "--". +// +// Integer flags accept 1234, 0664, 0x1234 and may be negative. +// Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. +// Duration flags accept any input valid for time.ParseDuration. +// +// The default set of command-line flags is controlled by +// top-level functions. The FlagSet type allows one to define +// independent sets of flags, such as to implement subcommands +// in a command-line interface. The methods of FlagSet are +// analogous to the top-level functions for the command-line +// flag set. + +package mflag + +import ( + "errors" + "fmt" + "io" + "os" + "sort" + "strconv" + "strings" + "text/tabwriter" + "time" +) + +// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +var ErrHelp = errors.New("flag: help requested") + +// ErrRetry is the error returned if you need to try letter by letter +var ErrRetry = errors.New("flag: retry") + +// -- bool Value +type boolValue bool + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val + return (*boolValue)(p) +} + +func (b *boolValue) Set(s string) error { + v, err := strconv.ParseBool(s) + *b = boolValue(v) + return err +} + +func (b *boolValue) Get() interface{} { return bool(*b) } + +func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } + +func (b *boolValue) IsBoolFlag() bool { return true } + +// optional interface to indicate boolean flags that can be +// supplied without "=value" text +type boolFlag interface { + Value + IsBoolFlag() bool +} + +// -- int Value +type intValue int + +func newIntValue(val int, p *int) *intValue { + *p = val + return (*intValue)(p) +} + +func (i *intValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = intValue(v) + return err +} + +func (i *intValue) Get() interface{} { return int(*i) } + +func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- int64 Value +type int64Value int64 + +func newInt64Value(val int64, p *int64) *int64Value { + *p = val + return (*int64Value)(p) +} + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = int64Value(v) + return err +} + +func (i *int64Value) Get() interface{} { return int64(*i) } + +func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint Value +type uintValue uint + +func newUintValue(val uint, p *uint) *uintValue { + *p = val + return (*uintValue)(p) +} + +func (i *uintValue) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uintValue(v) + return err +} + +func (i *uintValue) Get() interface{} { return uint(*i) } + +func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint64 Value +type uint64Value uint64 + +func newUint64Value(val uint64, p *uint64) *uint64Value { + *p = val + return (*uint64Value)(p) +} + +func (i *uint64Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uint64Value(v) + return err +} + +func (i *uint64Value) Get() interface{} { return uint64(*i) } + +func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint16 Value +type uint16Value uint16 + +func newUint16Value(val uint16, p *uint16) *uint16Value { + *p = val + return (*uint16Value)(p) +} + +func (i *uint16Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 16) + *i = uint16Value(v) + return err +} + +func (i *uint16Value) Get() interface{} { return uint16(*i) } + +func (i *uint16Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- string Value +type stringValue string + +func newStringValue(val string, p *string) *stringValue { + *p = val + return (*stringValue)(p) +} + +func (s *stringValue) Set(val string) error { + *s = stringValue(val) + return nil +} + +func (s *stringValue) Get() interface{} { return string(*s) } + +func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } + +// -- float64 Value +type float64Value float64 + +func newFloat64Value(val float64, p *float64) *float64Value { + *p = val + return (*float64Value)(p) +} + +func (f *float64Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 64) + *f = float64Value(v) + return err +} + +func (f *float64Value) Get() interface{} { return float64(*f) } + +func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } + +// -- time.Duration Value +type durationValue time.Duration + +func newDurationValue(val time.Duration, p *time.Duration) *durationValue { + *p = val + return (*durationValue)(p) +} + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(s) + *d = durationValue(v) + return err +} + +func (d *durationValue) Get() interface{} { return time.Duration(*d) } + +func (d *durationValue) String() string { return (*time.Duration)(d).String() } + +// Value is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +// +// If a Value has an IsBoolFlag() bool method returning true, +// the command-line parser makes -name equivalent to -name=true +// rather than using the next command-line argument. +type Value interface { + String() string + Set(string) error +} + +// Getter is an interface that allows the contents of a Value to be retrieved. +// It wraps the Value interface, rather than being part of it, because it +// appeared after Go 1 and its compatibility rules. All Value types provided +// by this package satisfy the Getter interface. +type Getter interface { + Value + Get() interface{} +} + +// ErrorHandling defines how to handle flag parsing errors. +type ErrorHandling int + +// ErrorHandling strategies available when a flag parsing error occurs +const ( + ContinueOnError ErrorHandling = iota + ExitOnError + PanicOnError +) + +// A FlagSet represents a set of defined flags. The zero value of a FlagSet +// has no name and has ContinueOnError error handling. +type FlagSet struct { + // Usage is the function called when an error occurs while parsing flags. + // The field is a function (not a method) that may be changed to point to + // a custom error handler. + Usage func() + ShortUsage func() + + name string + parsed bool + actual map[string]*Flag + formal map[string]*Flag + args []string // arguments after flags + errorHandling ErrorHandling + output io.Writer // nil means stderr; use Out() accessor + nArgRequirements []nArgRequirement +} + +// A Flag represents the state of a flag. +type Flag struct { + Names []string // name as it appears on command line + Usage string // help message + Value Value // value as set + DefValue string // default value (as text); for usage message +} + +type flagSlice []string + +func (p flagSlice) Len() int { return len(p) } +func (p flagSlice) Less(i, j int) bool { + pi, pj := strings.TrimPrefix(p[i], "-"), strings.TrimPrefix(p[j], "-") + lpi, lpj := strings.ToLower(pi), strings.ToLower(pj) + if lpi != lpj { + return lpi < lpj + } + return pi < pj +} +func (p flagSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// sortFlags returns the flags as a slice in lexicographical sorted order. +func sortFlags(flags map[string]*Flag) []*Flag { + var list flagSlice + + // The sorted list is based on the first name, when flag map might use the other names. + nameMap := make(map[string]string) + + for n, f := range flags { + fName := strings.TrimPrefix(f.Names[0], "#") + nameMap[fName] = n + if len(f.Names) == 1 { + list = append(list, fName) + continue + } + + found := false + for _, name := range list { + if name == fName { + found = true + break + } + } + if !found { + list = append(list, fName) + } + } + sort.Sort(list) + result := make([]*Flag, len(list)) + for i, name := range list { + result[i] = flags[nameMap[name]] + } + return result +} + +// Name returns the name of the FlagSet. +func (fs *FlagSet) Name() string { + return fs.name +} + +// Out returns the destination for usage and error messages. +func (fs *FlagSet) Out() io.Writer { + if fs.output == nil { + return os.Stderr + } + return fs.output +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (fs *FlagSet) SetOutput(output io.Writer) { + fs.output = output +} + +// VisitAll visits the flags in lexicographical order, calling fn for each. +// It visits all flags, even those not set. +func (fs *FlagSet) VisitAll(fn func(*Flag)) { + for _, flag := range sortFlags(fs.formal) { + fn(flag) + } +} + +// VisitAll visits the command-line flags in lexicographical order, calling +// fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + CommandLine.VisitAll(fn) +} + +// Visit visits the flags in lexicographical order, calling fn for each. +// It visits only those flags that have been set. +func (fs *FlagSet) Visit(fn func(*Flag)) { + for _, flag := range sortFlags(fs.actual) { + fn(flag) + } +} + +// Visit visits the command-line flags in lexicographical order, calling fn +// for each. It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + CommandLine.Visit(fn) +} + +// Lookup returns the Flag structure of the named flag, returning nil if none exists. +func (fs *FlagSet) Lookup(name string) *Flag { + return fs.formal[name] +} + +// IsSet indicates whether the specified flag is set in the given FlagSet +func (fs *FlagSet) IsSet(name string) bool { + return fs.actual[name] != nil +} + +// Lookup returns the Flag structure of the named command-line flag, +// returning nil if none exists. +func Lookup(name string) *Flag { + return CommandLine.formal[name] +} + +// IsSet indicates whether the specified flag was specified at all on the cmd line. +func IsSet(name string) bool { + return CommandLine.IsSet(name) +} + +type nArgRequirementType int + +// Indicator used to pass to BadArgs function +const ( + Exact nArgRequirementType = iota + Max + Min +) + +type nArgRequirement struct { + Type nArgRequirementType + N int +} + +// Require adds a requirement about the number of arguments for the FlagSet. +// The first parameter can be Exact, Max, or Min to respectively specify the exact, +// the maximum, or the minimal number of arguments required. +// The actual check is done in FlagSet.CheckArgs(). +func (fs *FlagSet) Require(nArgRequirementType nArgRequirementType, nArg int) { + fs.nArgRequirements = append(fs.nArgRequirements, nArgRequirement{nArgRequirementType, nArg}) +} + +// CheckArgs uses the requirements set by FlagSet.Require() to validate +// the number of arguments. If the requirements are not met, +// an error message string is returned. +func (fs *FlagSet) CheckArgs() (message string) { + for _, req := range fs.nArgRequirements { + var arguments string + if req.N == 1 { + arguments = "1 argument" + } else { + arguments = fmt.Sprintf("%d arguments", req.N) + } + + str := func(kind string) string { + return fmt.Sprintf("%q requires %s%s", fs.name, kind, arguments) + } + + switch req.Type { + case Exact: + if fs.NArg() != req.N { + return str("") + } + case Max: + if fs.NArg() > req.N { + return str("a maximum of ") + } + case Min: + if fs.NArg() < req.N { + return str("a minimum of ") + } + } + } + return "" +} + +// Set sets the value of the named flag. +func (fs *FlagSet) Set(name, value string) error { + flag, ok := fs.formal[name] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + if err := flag.Value.Set(value); err != nil { + return err + } + if fs.actual == nil { + fs.actual = make(map[string]*Flag) + } + fs.actual[name] = flag + return nil +} + +// Set sets the value of the named command-line flag. +func Set(name, value string) error { + return CommandLine.Set(name, value) +} + +// isZeroValue guesses whether the string represents the zero +// value for a flag. It is not accurate but in practice works OK. +func isZeroValue(value string) bool { + switch value { + case "false": + return true + case "": + return true + case "0": + return true + } + return false +} + +// PrintDefaults prints, to standard error unless configured +// otherwise, the default values of all defined flags in the set. +func (fs *FlagSet) PrintDefaults() { + writer := tabwriter.NewWriter(fs.Out(), 20, 1, 3, ' ', 0) + + // Add a blank line between cmd description and list of options + if fs.FlagCount() > 0 { + fmt.Fprintln(writer, "") + } + + fs.VisitAll(func(flag *Flag) { + names := []string{} + for _, name := range flag.Names { + if name[0] != '#' { + names = append(names, name) + } + } + if len(names) > 0 && len(flag.Usage) > 0 { + val := flag.DefValue + + if isZeroValue(val) { + format := " -%s" + fmt.Fprintf(writer, format, strings.Join(names, ", -")) + } else { + format := " -%s=%s" + fmt.Fprintf(writer, format, strings.Join(names, ", -"), val) + } + for _, line := range strings.Split(flag.Usage, "\n") { + fmt.Fprintln(writer, "\t", line) + } + } + }) + writer.Flush() +} + +// PrintDefaults prints to standard error the default values of all defined command-line flags. +func PrintDefaults() { + CommandLine.PrintDefaults() +} + +// defaultUsage is the default function to print a usage message. +func defaultUsage(fs *FlagSet) { + if fs.name == "" { + fmt.Fprintf(fs.Out(), "Usage:\n") + } else { + fmt.Fprintf(fs.Out(), "Usage of %s:\n", fs.name) + } + fs.PrintDefaults() +} + +// NOTE: Usage is not just defaultUsage(CommandLine) +// because it serves (via godoc flag Usage) as the example +// for how to write your own usage function. + +// Usage prints to standard error a usage message documenting all defined command-line flags. +// The function is a variable that may be changed to point to a custom function. +var Usage = func() { + fmt.Fprintf(CommandLine.Out(), "Usage of %s:\n", os.Args[0]) + PrintDefaults() +} + +// ShortUsage prints to standard error a usage message documenting the standard command layout +// The function is a variable that may be changed to point to a custom function. +var ShortUsage = func() { + fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0]) +} + +// FlagCount returns the number of flags that have been defined. +func (fs *FlagSet) FlagCount() int { return len(sortFlags(fs.formal)) } + +// FlagCountUndeprecated returns the number of undeprecated flags that have been defined. +func (fs *FlagSet) FlagCountUndeprecated() int { + count := 0 + for _, flag := range sortFlags(fs.formal) { + for _, name := range flag.Names { + if name[0] != '#' { + count++ + break + } + } + } + return count +} + +// NFlag returns the number of flags that have been set. +func (fs *FlagSet) NFlag() int { return len(fs.actual) } + +// NFlag returns the number of command-line flags that have been set. +func NFlag() int { return len(CommandLine.actual) } + +// Arg returns the i'th argument. Arg(0) is the first remaining argument +// after flags have been processed. +func (fs *FlagSet) Arg(i int) string { + if i < 0 || i >= len(fs.args) { + return "" + } + return fs.args[i] +} + +// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument +// after flags have been processed. +func Arg(i int) string { + return CommandLine.Arg(i) +} + +// NArg is the number of arguments remaining after flags have been processed. +func (fs *FlagSet) NArg() int { return len(fs.args) } + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(CommandLine.args) } + +// Args returns the non-flag arguments. +func (fs *FlagSet) Args() []string { return fs.args } + +// Args returns the non-flag command-line arguments. +func Args() []string { return CommandLine.args } + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func (fs *FlagSet) BoolVar(p *bool, names []string, value bool, usage string) { + fs.Var(newBoolValue(value, p), names, usage) +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func BoolVar(p *bool, names []string, value bool, usage string) { + CommandLine.Var(newBoolValue(value, p), names, usage) +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func (fs *FlagSet) Bool(names []string, value bool, usage string) *bool { + p := new(bool) + fs.BoolVar(p, names, value, usage) + return p +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(names []string, value bool, usage string) *bool { + return CommandLine.Bool(names, value, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func (fs *FlagSet) IntVar(p *int, names []string, value int, usage string) { + fs.Var(newIntValue(value, p), names, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func IntVar(p *int, names []string, value int, usage string) { + CommandLine.Var(newIntValue(value, p), names, usage) +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func (fs *FlagSet) Int(names []string, value int, usage string) *int { + p := new(int) + fs.IntVar(p, names, value, usage) + return p +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(names []string, value int, usage string) *int { + return CommandLine.Int(names, value, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func (fs *FlagSet) Int64Var(p *int64, names []string, value int64, usage string) { + fs.Var(newInt64Value(value, p), names, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func Int64Var(p *int64, names []string, value int64, usage string) { + CommandLine.Var(newInt64Value(value, p), names, usage) +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func (fs *FlagSet) Int64(names []string, value int64, usage string) *int64 { + p := new(int64) + fs.Int64Var(p, names, value, usage) + return p +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(names []string, value int64, usage string) *int64 { + return CommandLine.Int64(names, value, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (fs *FlagSet) UintVar(p *uint, names []string, value uint, usage string) { + fs.Var(newUintValue(value, p), names, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func UintVar(p *uint, names []string, value uint, usage string) { + CommandLine.Var(newUintValue(value, p), names, usage) +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (fs *FlagSet) Uint(names []string, value uint, usage string) *uint { + p := new(uint) + fs.UintVar(p, names, value, usage) + return p +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(names []string, value uint, usage string) *uint { + return CommandLine.Uint(names, value, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func (fs *FlagSet) Uint64Var(p *uint64, names []string, value uint64, usage string) { + fs.Var(newUint64Value(value, p), names, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func Uint64Var(p *uint64, names []string, value uint64, usage string) { + CommandLine.Var(newUint64Value(value, p), names, usage) +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func (fs *FlagSet) Uint64(names []string, value uint64, usage string) *uint64 { + p := new(uint64) + fs.Uint64Var(p, names, value, usage) + return p +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(names []string, value uint64, usage string) *uint64 { + return CommandLine.Uint64(names, value, usage) +} + +// Uint16Var defines a uint16 flag with specified name, default value, and usage string. +// The argument p points to a uint16 variable in which to store the value of the flag. +func (fs *FlagSet) Uint16Var(p *uint16, names []string, value uint16, usage string) { + fs.Var(newUint16Value(value, p), names, usage) +} + +// Uint16Var defines a uint16 flag with specified name, default value, and usage string. +// The argument p points to a uint16 variable in which to store the value of the flag. +func Uint16Var(p *uint16, names []string, value uint16, usage string) { + CommandLine.Var(newUint16Value(value, p), names, usage) +} + +// Uint16 defines a uint16 flag with specified name, default value, and usage string. +// The return value is the address of a uint16 variable that stores the value of the flag. +func (fs *FlagSet) Uint16(names []string, value uint16, usage string) *uint16 { + p := new(uint16) + fs.Uint16Var(p, names, value, usage) + return p +} + +// Uint16 defines a uint16 flag with specified name, default value, and usage string. +// The return value is the address of a uint16 variable that stores the value of the flag. +func Uint16(names []string, value uint16, usage string) *uint16 { + return CommandLine.Uint16(names, value, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func (fs *FlagSet) StringVar(p *string, names []string, value string, usage string) { + fs.Var(newStringValue(value, p), names, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func StringVar(p *string, names []string, value string, usage string) { + CommandLine.Var(newStringValue(value, p), names, usage) +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func (fs *FlagSet) String(names []string, value string, usage string) *string { + p := new(string) + fs.StringVar(p, names, value, usage) + return p +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(names []string, value string, usage string) *string { + return CommandLine.String(names, value, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func (fs *FlagSet) Float64Var(p *float64, names []string, value float64, usage string) { + fs.Var(newFloat64Value(value, p), names, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func Float64Var(p *float64, names []string, value float64, usage string) { + CommandLine.Var(newFloat64Value(value, p), names, usage) +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func (fs *FlagSet) Float64(names []string, value float64, usage string) *float64 { + p := new(float64) + fs.Float64Var(p, names, value, usage) + return p +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(names []string, value float64, usage string) *float64 { + return CommandLine.Float64(names, value, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func (fs *FlagSet) DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { + fs.Var(newDurationValue(value, p), names, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func DurationVar(p *time.Duration, names []string, value time.Duration, usage string) { + CommandLine.Var(newDurationValue(value, p), names, usage) +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func (fs *FlagSet) Duration(names []string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + fs.DurationVar(p, names, value, usage) + return p +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func Duration(names []string, value time.Duration, usage string) *time.Duration { + return CommandLine.Duration(names, value, usage) +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func (fs *FlagSet) Var(value Value, names []string, usage string) { + // Remember the default value as a string; it won't change. + flag := &Flag{names, usage, value, value.String()} + for _, name := range names { + name = strings.TrimPrefix(name, "#") + _, alreadythere := fs.formal[name] + if alreadythere { + var msg string + if fs.name == "" { + msg = fmt.Sprintf("flag redefined: %s", name) + } else { + msg = fmt.Sprintf("%s flag redefined: %s", fs.name, name) + } + fmt.Fprintln(fs.Out(), msg) + panic(msg) // Happens only if flags are declared with identical names + } + if fs.formal == nil { + fs.formal = make(map[string]*Flag) + } + fs.formal[name] = flag + } +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func Var(value Value, names []string, usage string) { + CommandLine.Var(value, names, usage) +} + +// failf prints to standard error a formatted error and usage message and +// returns the error. +func (fs *FlagSet) failf(format string, a ...interface{}) error { + err := fmt.Errorf(format, a...) + fmt.Fprintln(fs.Out(), err) + if os.Args[0] == fs.name { + fmt.Fprintf(fs.Out(), "See '%s --help'.\n", os.Args[0]) + } else { + fmt.Fprintf(fs.Out(), "See '%s %s --help'.\n", os.Args[0], fs.name) + } + return err +} + +// usage calls the Usage method for the flag set, or the usage function if +// the flag set is CommandLine. +func (fs *FlagSet) usage() { + if fs == CommandLine { + Usage() + } else if fs.Usage == nil { + defaultUsage(fs) + } else { + fs.Usage() + } +} + +func trimQuotes(str string) string { + if len(str) == 0 { + return str + } + type quote struct { + start, end byte + } + + // All valid quote types. + quotes := []quote{ + // Double quotes + { + start: '"', + end: '"', + }, + + // Single quotes + { + start: '\'', + end: '\'', + }, + } + + for _, quote := range quotes { + // Only strip if outermost match. + if str[0] == quote.start && str[len(str)-1] == quote.end { + str = str[1 : len(str)-1] + break + } + } + + return str +} + +// parseOne parses one flag. It reports whether a flag was seen. +func (fs *FlagSet) parseOne() (bool, string, error) { + if len(fs.args) == 0 { + return false, "", nil + } + s := fs.args[0] + if len(s) == 0 || s[0] != '-' || len(s) == 1 { + return false, "", nil + } + if s[1] == '-' && len(s) == 2 { // "--" terminates the flags + fs.args = fs.args[1:] + return false, "", nil + } + name := s[1:] + if len(name) == 0 || name[0] == '=' { + return false, "", fs.failf("bad flag syntax: %s", s) + } + + // it's a flag. does it have an argument? + fs.args = fs.args[1:] + hasValue := false + value := "" + if i := strings.Index(name, "="); i != -1 { + value = trimQuotes(name[i+1:]) + hasValue = true + name = name[:i] + } + + m := fs.formal + flag, alreadythere := m[name] // BUG + if !alreadythere { + if name == "-help" || name == "help" || name == "h" { // special case for nice help message. + fs.usage() + return false, "", ErrHelp + } + if len(name) > 0 && name[0] == '-' { + return false, "", fs.failf("flag provided but not defined: -%s", name) + } + return false, name, ErrRetry + } + if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg + if hasValue { + if err := fv.Set(value); err != nil { + return false, "", fs.failf("invalid boolean value %q for -%s: %v", value, name, err) + } + } else { + fv.Set("true") + } + } else { + // It must have a value, which might be the next argument. + if !hasValue && len(fs.args) > 0 { + // value is the next arg + hasValue = true + value, fs.args = fs.args[0], fs.args[1:] + } + if !hasValue { + return false, "", fs.failf("flag needs an argument: -%s", name) + } + if err := flag.Value.Set(value); err != nil { + return false, "", fs.failf("invalid value %q for flag -%s: %v", value, name, err) + } + } + if fs.actual == nil { + fs.actual = make(map[string]*Flag) + } + fs.actual[name] = flag + for i, n := range flag.Names { + if n == fmt.Sprintf("#%s", name) { + replacement := "" + for j := i; j < len(flag.Names); j++ { + if flag.Names[j][0] != '#' { + replacement = flag.Names[j] + break + } + } + if replacement != "" { + fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement) + } else { + fmt.Fprintf(fs.Out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name) + } + } + } + return true, "", nil +} + +// Parse parses flag definitions from the argument list, which should not +// include the command name. Must be called after all flags in the FlagSet +// are defined and before flags are accessed by the program. +// The return value will be ErrHelp if -help was set but not defined. +func (fs *FlagSet) Parse(arguments []string) error { + fs.parsed = true + fs.args = arguments + for { + seen, name, err := fs.parseOne() + if seen { + continue + } + if err == nil { + break + } + if err == ErrRetry { + if len(name) > 1 { + err = nil + for _, letter := range strings.Split(name, "") { + fs.args = append([]string{"-" + letter}, fs.args...) + seen2, _, err2 := fs.parseOne() + if seen2 { + continue + } + if err2 != nil { + err = fs.failf("flag provided but not defined: -%s", name) + break + } + } + if err == nil { + continue + } + } else { + err = fs.failf("flag provided but not defined: -%s", name) + } + } + switch fs.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(125) + case PanicOnError: + panic(err) + } + } + return nil +} + +// ParseFlags is a utility function that adds a help flag if withHelp is true, +// calls fs.Parse(args) and prints a relevant error message if there are +// incorrect number of arguments. It returns error only if error handling is +// set to ContinueOnError and parsing fails. If error handling is set to +// ExitOnError, it's safe to ignore the return value. +func (fs *FlagSet) ParseFlags(args []string, withHelp bool) error { + var help *bool + if withHelp { + help = fs.Bool([]string{"#help", "-help"}, false, "Print usage") + } + if err := fs.Parse(args); err != nil { + return err + } + if help != nil && *help { + fs.SetOutput(os.Stdout) + fs.Usage() + os.Exit(0) + } + if str := fs.CheckArgs(); str != "" { + fs.SetOutput(os.Stderr) + fs.ReportError(str, withHelp) + fs.ShortUsage() + os.Exit(1) + } + return nil +} + +// ReportError is a utility method that prints a user-friendly message +// containing the error that occurred during parsing and a suggestion to get help +func (fs *FlagSet) ReportError(str string, withHelp bool) { + if withHelp { + if os.Args[0] == fs.Name() { + str += ".\nSee '" + os.Args[0] + " --help'" + } else { + str += ".\nSee '" + os.Args[0] + " " + fs.Name() + " --help'" + } + } + fmt.Fprintf(fs.Out(), "%s: %s.\n", os.Args[0], str) +} + +// Parsed reports whether fs.Parse has been called. +func (fs *FlagSet) Parsed() bool { + return fs.parsed +} + +// Parse parses the command-line flags from os.Args[1:]. Must be called +// after all flags are defined and before flags are accessed by the program. +func Parse() { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.Parse(os.Args[1:]) +} + +// Parsed returns true if the command-line flags have been parsed. +func Parsed() bool { + return CommandLine.Parsed() +} + +// CommandLine is the default set of command-line flags, parsed from os.Args. +// The top-level functions such as BoolVar, Arg, and on are wrappers for the +// methods of CommandLine. +var CommandLine = NewFlagSet(os.Args[0], ExitOnError) + +// NewFlagSet returns a new, empty flag set with the specified name and +// error handling property. +func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { + f := &FlagSet{ + name: name, + errorHandling: errorHandling, + } + return f +} + +// Init sets the name and error handling property for a flag set. +// By default, the zero FlagSet uses an empty name and the +// ContinueOnError error handling policy. +func (fs *FlagSet) Init(name string, errorHandling ErrorHandling) { + fs.name = name + fs.errorHandling = errorHandling +} + +type mergeVal struct { + Value + key string + fset *FlagSet +} + +func (v mergeVal) Set(s string) error { + return v.fset.Set(v.key, s) +} + +func (v mergeVal) IsBoolFlag() bool { + if b, ok := v.Value.(boolFlag); ok { + return b.IsBoolFlag() + } + return false +} + +// Name returns the name of a mergeVal. +// If the original value had a name, return the original name, +// otherwise, return the key asinged to this mergeVal. +func (v mergeVal) Name() string { + type namedValue interface { + Name() string + } + if nVal, ok := v.Value.(namedValue); ok { + return nVal.Name() + } + return v.key +} + +// Merge is a helper function that merges n FlagSets into a single dest FlagSet +// In case of name collision between the flagsets it will apply +// the destination FlagSet's errorHandling behavior. +func Merge(dest *FlagSet, flagsets ...*FlagSet) error { + for _, fset := range flagsets { + if fset.formal == nil { + continue + } + for k, f := range fset.formal { + if _, ok := dest.formal[k]; ok { + var err error + if fset.name == "" { + err = fmt.Errorf("flag redefined: %s", k) + } else { + err = fmt.Errorf("%s flag redefined: %s", fset.name, k) + } + fmt.Fprintln(fset.Out(), err.Error()) + // Happens only if flags are declared with identical names + switch dest.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + newF := *f + newF.Value = mergeVal{f.Value, k, fset} + if dest.formal == nil { + dest.formal = make(map[string]*Flag) + } + dest.formal[k] = &newF + } + } + return nil +} + +// IsEmpty reports if the FlagSet is actually empty. +func (fs *FlagSet) IsEmpty() bool { + return len(fs.actual) == 0 +} diff --git a/vendor/github.com/weaveworks/common/mflagext/listvar.go b/vendor/github.com/weaveworks/common/mflagext/listvar.go new file mode 100644 index 000000000..892dac761 --- /dev/null +++ b/vendor/github.com/weaveworks/common/mflagext/listvar.go @@ -0,0 +1,34 @@ +package mflagext + +import ( + "fmt" + + "github.com/weaveworks/common/mflag" +) + +type listOpts struct { + value *[]string + hasBeenSet bool +} + +// ListVar creates an mflag.Var for repeated flags. +func ListVar(p *[]string, names []string, value []string, usage string) { + *p = value + mflag.Var(&listOpts{p, false}, names, usage) +} + +// Set implements mflag.Var +func (opts *listOpts) Set(value string) error { + if opts.hasBeenSet { + (*opts.value) = append((*opts.value), value) + } else { + (*opts.value) = []string{value} + opts.hasBeenSet = true + } + return nil +} + +// String implements mflag.Var +func (opts *listOpts) String() string { + return fmt.Sprintf("%v", []string(*opts.value)) +} diff --git a/vendor/github.com/weaveworks/common/middleware/grpc_auth.go b/vendor/github.com/weaveworks/common/middleware/grpc_auth.go new file mode 100644 index 000000000..634dd8e89 --- /dev/null +++ b/vendor/github.com/weaveworks/common/middleware/grpc_auth.go @@ -0,0 +1,58 @@ +package middleware + +import ( + "fmt" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "github.com/weaveworks/common/user" +) + +// ClientUserHeaderInterceptor propagates the user ID from the context to gRPC metadata, which eventually ends up as a HTTP2 header. +func ClientUserHeaderInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + userID, err := user.GetID(ctx) + if err != nil { + return err + } + + md, ok := metadata.FromContext(ctx) + if !ok { + md = metadata.New(map[string]string{}) + } + + newCtx := ctx + if userIDs, ok := md[user.LowerOrgIDHeaderName]; ok { + switch len(userIDs) { + case 1: + if userIDs[0] != userID { + return fmt.Errorf("wrong user ID found") + } + default: + return fmt.Errorf("multiple user IDs found") + } + } else { + md = md.Copy() + md[user.LowerOrgIDHeaderName] = []string{userID} + newCtx = metadata.NewContext(ctx, md) + } + + return invoker(newCtx, method, req, reply, cc, opts...) +} + +// ServerUserHeaderInterceptor propagates the user ID from the gRPC metadata back to our context. +func ServerUserHeaderInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + md, ok := metadata.FromContext(ctx) + if !ok { + return nil, fmt.Errorf("no metadata") + } + + userIDs, ok := md[user.LowerOrgIDHeaderName] + if !ok || len(userIDs) != 1 { + return nil, fmt.Errorf("no user id") + } + + newCtx := user.WithID(ctx, userIDs[0]) + return handler(newCtx, req) +} diff --git a/vendor/github.com/weaveworks/common/middleware/grpc_instrumentation.go b/vendor/github.com/weaveworks/common/middleware/grpc_instrumentation.go new file mode 100644 index 000000000..3d002be89 --- /dev/null +++ b/vendor/github.com/weaveworks/common/middleware/grpc_instrumentation.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +// ServerInstrumentInterceptor instruments gRPC requests for errors and latency. +func ServerInstrumentInterceptor(duration *prometheus.HistogramVec) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + begin := time.Now() + resp, err := handler(ctx, req) + status := "success" + if err != nil { + status = "error" + } + duration.WithLabelValues(gRPC, info.FullMethod, status, "false").Observe(time.Since(begin).Seconds()) + return resp, err + } +} diff --git a/vendor/github.com/weaveworks/common/middleware/grpc_logging.go b/vendor/github.com/weaveworks/common/middleware/grpc_logging.go new file mode 100644 index 000000000..1b3f4ef1f --- /dev/null +++ b/vendor/github.com/weaveworks/common/middleware/grpc_logging.go @@ -0,0 +1,25 @@ +package middleware + +import ( + "time" + + log "github.com/Sirupsen/logrus" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +const gRPC = "gRPC" + +// ServerLoggingInterceptor logs gRPC requests, errors and latency. +func ServerLoggingInterceptor(logSuccess bool) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + begin := time.Now() + resp, err := handler(ctx, req) + if err != nil { + log.Errorf("%s %s (%v) %s", gRPC, info.FullMethod, err, time.Since(begin)) + } else if logSuccess { + log.Infof("%s %s (success) %s", gRPC, info.FullMethod, time.Since(begin)) + } + return resp, err + } +} diff --git a/vendor/github.com/weaveworks/common/middleware/header_adder.go b/vendor/github.com/weaveworks/common/middleware/header_adder.go new file mode 100644 index 000000000..ce7f07df5 --- /dev/null +++ b/vendor/github.com/weaveworks/common/middleware/header_adder.go @@ -0,0 +1,25 @@ +package middleware + +import ( + "net/http" +) + +// HeaderAdder adds headers to responses +type HeaderAdder struct { + http.Header +} + +// Wrap implements Middleware +func (h HeaderAdder) Wrap(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do it in pre-order since headers need to be added before + // writing the response body + dst := w.Header() + for k, vv := range h.Header { + for _, v := range vv { + dst.Add(k, v) + } + } + next.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/weaveworks/common/middleware/instrument.go b/vendor/github.com/weaveworks/common/middleware/instrument.go index 6997920a2..875bb1da0 100644 --- a/vendor/github.com/weaveworks/common/middleware/instrument.go +++ b/vendor/github.com/weaveworks/common/middleware/instrument.go @@ -11,12 +11,15 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// RouteMatcher matches routes +type RouteMatcher interface { + Match(*http.Request, *mux.RouteMatch) bool +} + // Instrument is a Middleware which records timings for every HTTP request type Instrument struct { - RouteMatcher interface { - Match(*http.Request, *mux.RouteMatch) bool - } - Duration *prometheus.HistogramVec + RouteMatcher RouteMatcher + Duration *prometheus.HistogramVec } // IsWSHandshakeRequest returns true if the given request is a websocket handshake request. diff --git a/vendor/github.com/weaveworks/common/middleware/redirect.go b/vendor/github.com/weaveworks/common/middleware/redirect.go deleted file mode 100644 index 34c177281..000000000 --- a/vendor/github.com/weaveworks/common/middleware/redirect.go +++ /dev/null @@ -1,48 +0,0 @@ -package middleware - -import ( - "net/http" - "net/url" -) - -// Redirect middleware, will redirect requests to hosts which match any of the -// Matches to RedirectScheme://RedirectHost -type Redirect struct { - Matches []Match - - RedirectHost string - RedirectScheme string -} - -// Match specifies a match for a redirect. Host and/or Scheme can be empty -// signify match-all. -type Match struct { - Host, Scheme string -} - -func (m Match) match(u *url.URL) bool { - if m.Host != "" && m.Host != u.Host { - return false - } - - if m.Scheme != "" && m.Scheme != u.Scheme { - return false - } - - return true -} - -// Wrap implements Middleware -func (m Redirect) Wrap(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - for _, match := range m.Matches { - if match.match(r.URL) { - r.URL.Host = m.RedirectHost - r.URL.Scheme = m.RedirectScheme - http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently) - return - } - } - next.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/weaveworks/common/signals/signals.go b/vendor/github.com/weaveworks/common/signals/signals.go new file mode 100644 index 000000000..61a3ceb2c --- /dev/null +++ b/vendor/github.com/weaveworks/common/signals/signals.go @@ -0,0 +1,41 @@ +package signals + +import ( + "os" + "os/signal" + "runtime" + "syscall" +) + +// SignalReceiver represents a subsystem/server/... that can be stopped or +// queried about the status with a signal +type SignalReceiver interface { + Stop() error +} + +// Logger is something to log too. +type Logger interface { + Infof(format string, args ...interface{}) +} + +// SignalHandlerLoop blocks until it receives a SIGINT, SIGTERM or SIGQUIT. +// For SIGINT and SIGTERM, it exits; for SIGQUIT is print a goroutine stack +// dump. +func SignalHandlerLoop(log Logger, ss ...SignalReceiver) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) + buf := make([]byte, 1<<20) + for { + switch <-sigs { + case syscall.SIGINT, syscall.SIGTERM: + log.Infof("=== received SIGINT/SIGTERM ===\n*** exiting") + for _, subsystem := range ss { + subsystem.Stop() + } + return + case syscall.SIGQUIT: + stacklen := runtime.Stack(buf, true) + log.Infof("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:stacklen]) + } + } +} diff --git a/vendor/github.com/weaveworks/common/test/exec/exec.go b/vendor/github.com/weaveworks/common/test/exec/exec.go index 6e6d9cc89..58b04904f 100644 --- a/vendor/github.com/weaveworks/common/test/exec/exec.go +++ b/vendor/github.com/weaveworks/common/test/exec/exec.go @@ -68,6 +68,8 @@ func (c *mockCmd) Run() error { return nil } +func (c *mockCmd) SetEnv([]string) {} + func (b *blockingReader) Read(p []byte) (n int, err error) { <-b.quit return 0, nil diff --git a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/cli.go b/vendor/github.com/weaveworks/common/tools/cmd/wcloud/cli.go deleted file mode 100644 index ba3c355fd..000000000 --- a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/cli.go +++ /dev/null @@ -1,238 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "os" - "os/user" - "path/filepath" - "strings" - "time" - - "github.com/olekukonko/tablewriter" - "gopkg.in/yaml.v2" -) - -// ArrayFlags allows you to collect repeated flags -type ArrayFlags []string - -func (a *ArrayFlags) String() string { - return strings.Join(*a, ",") -} - -// Set implements flags.Value -func (a *ArrayFlags) Set(value string) error { - *a = append(*a, value) - return nil -} - -func env(key, def string) string { - if val, ok := os.LookupEnv(key); ok { - return val - } - return def -} - -var ( - token = env("SERVICE_TOKEN", "") - baseURL = env("BASE_URL", "https://cloud.weave.works") -) - -func usage() { - fmt.Println(`Usage: - deploy : Deploy image to your configured env - list List recent deployments - config () Get (or set) the configured env - logs Show lots for the given deployment`) -} - -func main() { - if len(os.Args) <= 1 { - usage() - os.Exit(1) - } - - c := NewClient(token, baseURL) - - switch os.Args[1] { - case "deploy": - deploy(c, os.Args[2:]) - case "list": - list(c, os.Args[2:]) - case "config": - config(c, os.Args[2:]) - case "logs": - logs(c, os.Args[2:]) - case "events": - events(c, os.Args[2:]) - case "help": - usage() - default: - usage() - } -} - -func deploy(c Client, args []string) { - var ( - flags = flag.NewFlagSet("", flag.ContinueOnError) - username = flags.String("u", "", "Username to report to deploy service (default with be current user)") - services ArrayFlags - ) - flags.Var(&services, "service", "Service to update (can be repeated)") - if err := flags.Parse(args); err != nil { - usage() - return - } - args = flags.Args() - if len(args) != 1 { - usage() - return - } - parts := strings.SplitN(args[0], ":", 2) - if len(parts) < 2 { - usage() - return - } - if *username == "" { - user, err := user.Current() - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - *username = user.Username - } - deployment := Deployment{ - ImageName: parts[0], - Version: parts[1], - TriggeringUser: *username, - IntendedServices: services, - } - if err := c.Deploy(deployment); err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } -} - -func list(c Client, args []string) { - var ( - flags = flag.NewFlagSet("", flag.ContinueOnError) - since = flags.Duration("since", 7*24*time.Hour, "How far back to fetch results") - ) - if err := flags.Parse(args); err != nil { - usage() - return - } - through := time.Now() - from := through.Add(-*since) - deployments, err := c.GetDeployments(from.Unix(), through.Unix()) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Created", "ID", "Image", "Version", "State"}) - table.SetBorder(false) - table.SetColumnSeparator(" ") - for _, deployment := range deployments { - table.Append([]string{ - deployment.CreatedAt.Format(time.RFC822), - deployment.ID, - deployment.ImageName, - deployment.Version, - deployment.State, - }) - } - table.Render() -} - -func events(c Client, args []string) { - var ( - flags = flag.NewFlagSet("", flag.ContinueOnError) - since = flags.Duration("since", 7*24*time.Hour, "How far back to fetch results") - ) - if err := flags.Parse(args); err != nil { - usage() - return - } - through := time.Now() - from := through.Add(-*since) - events, err := c.GetEvents(from.Unix(), through.Unix()) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - fmt.Println("events: ", string(events)) -} - -func loadConfig(filename string) (*Config, error) { - extension := filepath.Ext(filename) - var config Config - buf, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - if extension == ".yaml" || extension == ".yml" { - if err := yaml.Unmarshal(buf, &config); err != nil { - return nil, err - } - } else { - if err := json.NewDecoder(bytes.NewReader(buf)).Decode(&config); err != nil { - return nil, err - } - } - return &config, nil -} - -func config(c Client, args []string) { - if len(args) > 1 { - usage() - return - } - - if len(args) == 1 { - config, err := loadConfig(args[0]) - if err != nil { - fmt.Println("Error reading config:", err) - os.Exit(1) - } - - if err := c.SetConfig(config); err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - } else { - config, err := c.GetConfig() - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - buf, err := yaml.Marshal(config) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - fmt.Println(string(buf)) - } -} - -func logs(c Client, args []string) { - if len(args) != 1 { - usage() - return - } - - output, err := c.GetLogs(args[0]) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - fmt.Println(string(output)) -} diff --git a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/client.go b/vendor/github.com/weaveworks/common/tools/cmd/wcloud/client.go deleted file mode 100644 index 02cbbaa74..000000000 --- a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/client.go +++ /dev/null @@ -1,150 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" -) - -// Client for the deployment service -type Client struct { - token string - baseURL string -} - -// NewClient makes a new Client -func NewClient(token, baseURL string) Client { - return Client{ - token: token, - baseURL: baseURL, - } -} - -func (c Client) newRequest(method, path string, body io.Reader) (*http.Request, error) { - req, err := http.NewRequest(method, c.baseURL+path, body) - if err != nil { - return nil, err - } - req.Header.Add("Authorization", fmt.Sprintf("Scope-Probe token=%s", c.token)) - return req, nil -} - -// Deploy notifies the deployment service about a new deployment -func (c Client) Deploy(deployment Deployment) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(deployment); err != nil { - return err - } - req, err := c.newRequest("POST", "/api/deploy/deploy", &buf) - if err != nil { - return err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - if res.StatusCode != 204 { - return fmt.Errorf("error making request: %s", res.Status) - } - return nil -} - -// GetDeployments returns a list of deployments -func (c Client) GetDeployments(from, through int64) ([]Deployment, error) { - req, err := c.newRequest("GET", fmt.Sprintf("/api/deploy/deploy?from=%d&through=%d", from, through), nil) - if err != nil { - return nil, err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("error making request: %s", res.Status) - } - var response struct { - Deployments []Deployment `json:"deployments"` - } - if err := json.NewDecoder(res.Body).Decode(&response); err != nil { - return nil, err - } - return response.Deployments, nil -} - -// GetEvents returns the raw events. -func (c Client) GetEvents(from, through int64) ([]byte, error) { - req, err := c.newRequest("GET", fmt.Sprintf("/api/deploy/event?from=%d&through=%d", from, through), nil) - if err != nil { - return nil, err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("error making request: %s", res.Status) - } - return ioutil.ReadAll(res.Body) -} - -// GetConfig returns the current Config -func (c Client) GetConfig() (*Config, error) { - req, err := c.newRequest("GET", "/api/config/deploy", nil) - if err != nil { - return nil, err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode == 404 { - return nil, fmt.Errorf("no configuration uploaded yet") - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("error making request: %s", res.Status) - } - var config Config - if err := json.NewDecoder(res.Body).Decode(&config); err != nil { - return nil, err - } - return &config, nil -} - -// SetConfig sets the current Config -func (c Client) SetConfig(config *Config) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(config); err != nil { - return err - } - req, err := c.newRequest("POST", "/api/config/deploy", &buf) - if err != nil { - return err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - if res.StatusCode != 204 { - return fmt.Errorf("error making request: %s", res.Status) - } - return nil -} - -// GetLogs returns the logs for a given deployment. -func (c Client) GetLogs(deployID string) ([]byte, error) { - req, err := c.newRequest("GET", fmt.Sprintf("/api/deploy/deploy/%s/log", deployID), nil) - if err != nil { - return nil, err - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("error making request: %s", res.Status) - } - return ioutil.ReadAll(res.Body) -} diff --git a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/types.go b/vendor/github.com/weaveworks/common/tools/cmd/wcloud/types.go deleted file mode 100644 index a068163c3..000000000 --- a/vendor/github.com/weaveworks/common/tools/cmd/wcloud/types.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "time" -) - -// Deployment describes a deployment -type Deployment struct { - ID string `json:"id"` - CreatedAt time.Time `json:"created_at"` - ImageName string `json:"image_name"` - Version string `json:"version"` - Priority int `json:"priority"` - State string `json:"status"` - - TriggeringUser string `json:"triggering_user"` - IntendedServices []string `json:"intended_services"` -} - -// Config for the deployment system for a user. -type Config struct { - RepoURL string `json:"repo_url" yaml:"repo_url"` - RepoBranch string `json:"repo_branch" yaml:"repo_branch"` - RepoPath string `json:"repo_path" yaml:"repo_path"` - RepoKey string `json:"repo_key" yaml:"repo_key"` - KubeconfigPath string `json:"kubeconfig_path" yaml:"kubeconfig_path"` - AutoApply bool `json:"auto_apply" yaml:"auto_apply"` - - Notifications []NotificationConfig `json:"notifications" yaml:"notifications"` - - // Globs of files not to change, relative to the route of the repo - ConfigFileBlackList []string `json:"config_file_black_list" yaml:"config_file_black_list"` - - CommitMessageTemplate string `json:"commit_message_template" yaml:"commit_message_template"` // See https://golang.org/pkg/text/template/ -} - -// NotificationConfig describes how to send notifications -type NotificationConfig struct { - SlackWebhookURL string `json:"slack_webhook_url" yaml:"slack_webhook_url"` - SlackUsername string `json:"slack_username" yaml:"slack_username"` - MessageTemplate string `json:"message_template" yaml:"message_template"` - ApplyMessageTemplate string `json:"apply_message_template" yaml:"apply_message_template"` -} diff --git a/vendor/github.com/weaveworks/common/tools/runner/runner.go b/vendor/github.com/weaveworks/common/tools/runner/runner.go index c92ac6b5b..42f10b181 100644 --- a/vendor/github.com/weaveworks/common/tools/runner/runner.go +++ b/vendor/github.com/weaveworks/common/tools/runner/runner.go @@ -15,7 +15,7 @@ import ( "time" "github.com/mgutz/ansi" - "github.com/weaveworks/docker/pkg/mflag" + "github.com/weaveworks/common/mflag" ) const ( diff --git a/vendor/github.com/weaveworks/common/tools/socks/main.go b/vendor/github.com/weaveworks/common/tools/socks/main.go index 83a214980..7cd8c7086 100644 --- a/vendor/github.com/weaveworks/common/tools/socks/main.go +++ b/vendor/github.com/weaveworks/common/tools/socks/main.go @@ -9,8 +9,8 @@ import ( "text/template" socks5 "github.com/armon/go-socks5" - "github.com/weaveworks/docker/pkg/mflag" - "github.com/weaveworks/weave/common/mflagext" + "github.com/weaveworks/common/mflag" + "github.com/weaveworks/common/mflagext" "golang.org/x/net/context" ) diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/cmd/shfmt/main.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/cmd/shfmt/main.go deleted file mode 100644 index 08f99e013..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/cmd/shfmt/main.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package main - -import ( - "bytes" - "flag" - "fmt" - "io" - "log" - "os" - "path/filepath" - "regexp" - "runtime/pprof" - "strings" - - "github.com/mvdan/sh/syntax" -) - -var ( - write = flag.Bool("w", false, "write result to file instead of stdout") - list = flag.Bool("l", false, "list files whose formatting differs from shfmt's") - indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces") - posix = flag.Bool("p", false, "parse POSIX shell code instead of bash") - cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") - - parseMode syntax.ParseMode - printConfig syntax.PrintConfig - readBuf, writeBuf bytes.Buffer - - out io.Writer -) - -func main() { - flag.Parse() - if *cpuprofile != "" { - f, err := os.Create(*cpuprofile) - if err != nil { - log.Fatal(err) - } - pprof.StartCPUProfile(f) - defer pprof.StopCPUProfile() - } - - out = os.Stdout - printConfig.Spaces = *indent - parseMode |= syntax.ParseComments - if *posix { - parseMode |= syntax.PosixConformant - } - if flag.NArg() == 0 { - if err := formatStdin(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - return - } - anyErr := false - onError := func(err error) { - anyErr = true - fmt.Fprintln(os.Stderr, err) - } - for _, path := range flag.Args() { - walk(path, onError) - } - if anyErr { - os.Exit(1) - } -} - -func formatStdin() error { - if *write || *list { - return fmt.Errorf("-w and -l can only be used on files") - } - readBuf.Reset() - if _, err := io.Copy(&readBuf, os.Stdin); err != nil { - return err - } - src := readBuf.Bytes() - prog, err := syntax.Parse(src, "", parseMode) - if err != nil { - return err - } - return printConfig.Fprint(out, prog) -} - -var ( - shellFile = regexp.MustCompile(`\.(sh|bash)$`) - validShebang = regexp.MustCompile(`^#!\s?/(usr/)?bin/(env *)?(sh|bash)`) - vcsDir = regexp.MustCompile(`^\.(git|svn|hg)$`) -) - -type shellConfidence int - -const ( - notShellFile shellConfidence = iota - ifValidShebang - isShellFile -) - -func getConfidence(info os.FileInfo) shellConfidence { - name := info.Name() - switch { - case info.IsDir(), name[0] == '.', !info.Mode().IsRegular(): - return notShellFile - case shellFile.MatchString(name): - return isShellFile - case strings.Contains(name, "."): - return notShellFile // different extension - case info.Size() < 8: - return notShellFile // cannot possibly hold valid shebang - default: - return ifValidShebang - } -} - -func walk(path string, onError func(error)) { - info, err := os.Stat(path) - if err != nil { - onError(err) - return - } - if !info.IsDir() { - if err := formatPath(path, false); err != nil { - onError(err) - } - return - } - filepath.Walk(path, func(path string, info os.FileInfo, err error) error { - if info.IsDir() && vcsDir.MatchString(info.Name()) { - return filepath.SkipDir - } - if err != nil { - onError(err) - return nil - } - conf := getConfidence(info) - if conf == notShellFile { - return nil - } - err = formatPath(path, conf == ifValidShebang) - if err != nil && !os.IsNotExist(err) { - onError(err) - } - return nil - }) -} - -func empty(f *os.File) error { - if err := f.Truncate(0); err != nil { - return err - } - _, err := f.Seek(0, 0) - return err -} - -func formatPath(path string, checkShebang bool) error { - openMode := os.O_RDONLY - if *write { - openMode = os.O_RDWR - } - f, err := os.OpenFile(path, openMode, 0) - if err != nil { - return err - } - defer f.Close() - readBuf.Reset() - if _, err := io.Copy(&readBuf, f); err != nil { - return err - } - src := readBuf.Bytes() - if checkShebang && !validShebang.Match(src[:32]) { - return nil - } - prog, err := syntax.Parse(src, path, parseMode) - if err != nil { - return err - } - writeBuf.Reset() - printConfig.Fprint(&writeBuf, prog) - res := writeBuf.Bytes() - if !bytes.Equal(src, res) { - if *list { - fmt.Fprintln(out, path) - } - if *write { - if err := empty(f); err != nil { - return err - } - if _, err := f.Write(res); err != nil { - return err - } - } - } - if !*list && !*write { - if _, err := out.Write(res); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/doc.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/doc.go deleted file mode 100644 index eff8c2fec..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -// Package syntax implements parsing and formatting of shell programs. -// It supports both POSIX Shell and Bash. -package syntax diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/lexer.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/lexer.go deleted file mode 100644 index 8b5cbd3a1..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/lexer.go +++ /dev/null @@ -1,962 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -import ( - "bytes" -) - -// bytes that form or start a token -func regOps(b byte) bool { - return b == ';' || b == '"' || b == '\'' || b == '(' || - b == ')' || b == '$' || b == '|' || b == '&' || - b == '>' || b == '<' || b == '`' -} - -// tokenize these inside parameter expansions -func paramOps(b byte) bool { - return b == '}' || b == '#' || b == ':' || b == '-' || b == '+' || - b == '=' || b == '?' || b == '%' || b == '[' || b == '/' || - b == '^' || b == ',' -} - -// tokenize these inside arithmetic expansions -func arithmOps(b byte) bool { - return b == '+' || b == '-' || b == '!' || b == '*' || - b == '/' || b == '%' || b == '(' || b == ')' || - b == '^' || b == '<' || b == '>' || b == ':' || - b == '=' || b == ',' || b == '?' || b == '|' || - b == '&' -} - -func wordBreak(b byte) bool { - return b == ' ' || b == '\t' || b == '\r' || b == '\n' || - b == '&' || b == '>' || b == '<' || b == '|' || - b == ';' || b == '(' || b == ')' -} - -func (p *parser) next() { - if p.tok == _EOF || p.npos >= len(p.src) { - p.tok = _EOF - return - } - p.spaced, p.newLine = false, false - b, q := p.src[p.npos], p.quote - p.pos = Pos(p.npos + 1) - switch q { - case hdocWord: - if wordBreak(b) { - p.tok = illegalTok - p.spaced = true - return - } - case paramExpRepl: - switch b { - case '}': - p.npos++ - p.tok = rightBrace - case '/': - p.npos++ - p.tok = Quo - case '`', '"', '$': - p.tok = p.dqToken(b) - default: - p.advanceLitOther(q) - } - return - case dblQuotes: - if b == '`' || b == '"' || b == '$' { - p.tok = p.dqToken(b) - } else { - p.advanceLitDquote() - } - return - case hdocBody, hdocBodyTabs: - if b == '`' || b == '$' { - p.tok = p.dqToken(b) - } else if p.hdocStop == nil { - p.tok = illegalTok - } else { - p.advanceLitHdoc() - } - return - case paramExpExp: - switch b { - case '}': - p.npos++ - p.tok = rightBrace - case '`', '"', '$': - p.tok = p.dqToken(b) - default: - p.advanceLitOther(q) - } - return - case sglQuotes: - if b == '\'' { - p.npos++ - p.tok = sglQuote - } else { - p.advanceLitOther(q) - } - return - } -skipSpace: - for { - switch b { - case ' ', '\t', '\r': - p.spaced = true - p.npos++ - case '\n': - if p.quote == arithmExprLet { - p.tok = illegalTok - p.newLine, p.spaced = true, true - return - } - p.spaced = true - if p.npos < len(p.src) { - p.npos++ - } - p.f.Lines = append(p.f.Lines, p.npos) - p.newLine = true - if len(p.heredocs) > p.buriedHdocs { - p.doHeredocs() - if p.tok == _EOF { - return - } - } - case '\\': - if p.npos < len(p.src)-1 && p.src[p.npos+1] == '\n' { - p.npos += 2 - p.f.Lines = append(p.f.Lines, p.npos) - } else { - break skipSpace - } - default: - break skipSpace - } - if p.npos >= len(p.src) { - p.tok = _EOF - return - } - b = p.src[p.npos] - } - p.pos = Pos(p.npos + 1) - switch { - case q&allRegTokens != 0: - switch b { - case ';', '"', '\'', '(', ')', '$', '|', '&', '>', '<', '`': - p.tok = p.regToken(b) - case '#': - p.npos++ - bs, _ := p.readUntil('\n') - p.npos += len(bs) - if p.mode&ParseComments > 0 { - p.f.Comments = append(p.f.Comments, &Comment{ - Hash: p.pos, - Text: string(bs), - }) - } - p.next() - case '?', '*', '+', '@', '!': - if p.bash() && p.npos+1 < len(p.src) && p.src[p.npos+1] == '(' { - switch b { - case '?': - p.tok = globQuest - case '*': - p.tok = globMul - case '+': - p.tok = globAdd - case '@': - p.tok = globAt - default: // '!' - p.tok = globNot - } - p.npos += 2 - } else { - p.advanceLitNone() - } - default: - p.advanceLitNone() - } - case q == paramExpName && paramOps(b): - p.tok = p.paramToken(b) - case q&allArithmExpr != 0 && arithmOps(b): - p.tok = p.arithmToken(b) - case q&allRbrack != 0 && b == ']': - p.npos++ - p.tok = rightBrack - case q == testRegexp: - p.advanceLitRe() - case regOps(b): - p.tok = p.regToken(b) - default: - p.advanceLitOther(q) - } -} - -func byteAt(src []byte, i int) byte { - if i >= len(src) { - return 0 - } - return src[i] -} - -func (p *parser) regToken(b byte) Token { - switch b { - case '\'': - p.npos++ - return sglQuote - case '"': - p.npos++ - return dblQuote - case '`': - p.npos++ - return bckQuote - case '&': - switch byteAt(p.src, p.npos+1) { - case '&': - p.npos += 2 - return AndExpr - case '>': - if !p.bash() { - break - } - if byteAt(p.src, p.npos+2) == '>' { - p.npos += 3 - return appAll - } - p.npos += 2 - return rdrAll - } - p.npos++ - return And - case '|': - switch byteAt(p.src, p.npos+1) { - case '|': - p.npos += 2 - return OrExpr - case '&': - if !p.bash() { - break - } - p.npos += 2 - return pipeAll - } - p.npos++ - return Or - case '$': - switch byteAt(p.src, p.npos+1) { - case '\'': - if !p.bash() { - break - } - p.npos += 2 - return dollSglQuote - case '"': - if !p.bash() { - break - } - p.npos += 2 - return dollDblQuote - case '{': - p.npos += 2 - return dollBrace - case '[': - if !p.bash() { - break - } - p.npos += 2 - return dollBrack - case '(': - if byteAt(p.src, p.npos+2) == '(' { - p.npos += 3 - return dollDblParen - } - p.npos += 2 - return dollParen - } - p.npos++ - return dollar - case '(': - if p.bash() && byteAt(p.src, p.npos+1) == '(' { - p.npos += 2 - return dblLeftParen - } - p.npos++ - return leftParen - case ')': - p.npos++ - return rightParen - case ';': - switch byteAt(p.src, p.npos+1) { - case ';': - if p.bash() && byteAt(p.src, p.npos+2) == '&' { - p.npos += 3 - return dblSemiFall - } - p.npos += 2 - return dblSemicolon - case '&': - if !p.bash() { - break - } - p.npos += 2 - return semiFall - } - p.npos++ - return semicolon - case '<': - switch byteAt(p.src, p.npos+1) { - case '<': - if b := byteAt(p.src, p.npos+2); b == '-' { - p.npos += 3 - return dashHdoc - } else if p.bash() && b == '<' { - p.npos += 3 - return wordHdoc - } - p.npos += 2 - return Shl - case '>': - p.npos += 2 - return rdrInOut - case '&': - p.npos += 2 - return dplIn - case '(': - if !p.bash() { - break - } - p.npos += 2 - return cmdIn - } - p.npos++ - return Lss - default: // '>' - switch byteAt(p.src, p.npos+1) { - case '>': - p.npos += 2 - return Shr - case '&': - p.npos += 2 - return dplOut - case '|': - p.npos += 2 - return clbOut - case '(': - if !p.bash() { - break - } - p.npos += 2 - return cmdOut - } - p.npos++ - return Gtr - } -} - -func (p *parser) dqToken(b byte) Token { - switch b { - case '"': - p.npos++ - return dblQuote - case '`': - p.npos++ - return bckQuote - default: // '$' - switch byteAt(p.src, p.npos+1) { - case '{': - p.npos += 2 - return dollBrace - case '[': - if !p.bash() { - break - } - p.npos += 2 - return dollBrack - case '(': - if byteAt(p.src, p.npos+2) == '(' { - p.npos += 3 - return dollDblParen - } - p.npos += 2 - return dollParen - } - p.npos++ - return dollar - } -} - -func (p *parser) paramToken(b byte) Token { - switch b { - case '}': - p.npos++ - return rightBrace - case ':': - switch byteAt(p.src, p.npos+1) { - case '+': - p.npos += 2 - return ColAdd - case '-': - p.npos += 2 - return ColSub - case '?': - p.npos += 2 - return ColQuest - case '=': - p.npos += 2 - return ColAssgn - } - p.npos++ - return Colon - case '+': - p.npos++ - return Add - case '-': - p.npos++ - return Sub - case '?': - p.npos++ - return Quest - case '=': - p.npos++ - return Assgn - case '%': - if byteAt(p.src, p.npos+1) == '%' { - p.npos += 2 - return dblRem - } - p.npos++ - return Rem - case '#': - if byteAt(p.src, p.npos+1) == '#' { - p.npos += 2 - return dblHash - } - p.npos++ - return Hash - case '[': - p.npos++ - return leftBrack - case '^': - if byteAt(p.src, p.npos+1) == '^' { - p.npos += 2 - return dblXor - } - p.npos++ - return Xor - case ',': - if byteAt(p.src, p.npos+1) == ',' { - p.npos += 2 - return dblComma - } - p.npos++ - return Comma - default: // '/' - if byteAt(p.src, p.npos+1) == '/' { - p.npos += 2 - return dblQuo - } - p.npos++ - return Quo - } -} - -func (p *parser) arithmToken(b byte) Token { - switch b { - case '!': - if byteAt(p.src, p.npos+1) == '=' { - p.npos += 2 - return Neq - } - p.npos++ - return Not - case '=': - if byteAt(p.src, p.npos+1) == '=' { - p.npos += 2 - return Eql - } - p.npos++ - return Assgn - case '(': - p.npos++ - return leftParen - case ')': - p.npos++ - return rightParen - case '&': - switch byteAt(p.src, p.npos+1) { - case '&': - p.npos += 2 - return AndExpr - case '=': - p.npos += 2 - return AndAssgn - } - p.npos++ - return And - case '|': - switch byteAt(p.src, p.npos+1) { - case '|': - p.npos += 2 - return OrExpr - case '=': - p.npos += 2 - return OrAssgn - } - p.npos++ - return Or - case '<': - switch byteAt(p.src, p.npos+1) { - case '<': - if byteAt(p.src, p.npos+2) == '=' { - p.npos += 3 - return ShlAssgn - } - p.npos += 2 - return Shl - case '=': - p.npos += 2 - return Leq - } - p.npos++ - return Lss - case '>': - switch byteAt(p.src, p.npos+1) { - case '>': - if byteAt(p.src, p.npos+2) == '=' { - p.npos += 3 - return ShrAssgn - } - p.npos += 2 - return Shr - case '=': - p.npos += 2 - return Geq - } - p.npos++ - return Gtr - case '+': - switch byteAt(p.src, p.npos+1) { - case '+': - p.npos += 2 - return Inc - case '=': - p.npos += 2 - return AddAssgn - } - p.npos++ - return Add - case '-': - switch byteAt(p.src, p.npos+1) { - case '-': - p.npos += 2 - return Dec - case '=': - p.npos += 2 - return SubAssgn - } - p.npos++ - return Sub - case '%': - if byteAt(p.src, p.npos+1) == '=' { - p.npos += 2 - return RemAssgn - } - p.npos++ - return Rem - case '*': - switch byteAt(p.src, p.npos+1) { - case '*': - p.npos += 2 - return Pow - case '=': - p.npos += 2 - return MulAssgn - } - p.npos++ - return Mul - case '/': - if byteAt(p.src, p.npos+1) == '=' { - p.npos += 2 - return QuoAssgn - } - p.npos++ - return Quo - case '^': - if byteAt(p.src, p.npos+1) == '=' { - p.npos += 2 - return XorAssgn - } - p.npos++ - return Xor - case ',': - p.npos++ - return Comma - case '?': - p.npos++ - return Quest - default: // ':' - p.npos++ - return Colon - } -} - -func (p *parser) advanceLitOther(q quoteState) { - bs := p.litBuf[:0] - for { - if p.npos >= len(p.src) { - p.tok, p.val = _LitWord, string(bs) - return - } - b := p.src[p.npos] - switch { - case b == '\\': // escaped byte follows - if p.npos == len(p.src)-1 { - p.npos++ - bs = append(bs, '\\') - p.tok, p.val = _LitWord, string(bs) - return - } - b = p.src[p.npos+1] - p.npos += 2 - if b == '\n' { - p.f.Lines = append(p.f.Lines, p.npos) - } else { - bs = append(bs, '\\', b) - } - continue - case q == sglQuotes: - switch b { - case '\n': - p.f.Lines = append(p.f.Lines, p.npos+1) - case '\'': - p.tok, p.val = _LitWord, string(bs) - return - } - case b == '`', b == '$': - p.tok, p.val = _Lit, string(bs) - return - case q == paramExpExp: - if b == '}' { - p.tok, p.val = _LitWord, string(bs) - return - } else if b == '"' { - p.tok, p.val = _Lit, string(bs) - return - } - case q == paramExpRepl: - if b == '}' || b == '/' { - p.tok, p.val = _LitWord, string(bs) - return - } - case wordBreak(b), regOps(b), q&allArithmExpr != 0 && arithmOps(b), - q == paramExpName && paramOps(b), - q&allRbrack != 0 && b == ']': - p.tok, p.val = _LitWord, string(bs) - return - } - bs = append(bs, p.src[p.npos]) - p.npos++ - } -} - -func (p *parser) advanceLitNone() { - var i int - tok := _Lit - p.asPos = 0 -loop: - for i = p.npos; i < len(p.src); i++ { - switch p.src[i] { - case '\\': // escaped byte follows - if i == len(p.src)-1 { - break - } - if i++; p.src[i] == '\n' { - p.f.Lines = append(p.f.Lines, i+1) - bs := p.src[p.npos : i-1] - p.npos = i + 1 - p.advanceLitNoneCont(bs) - return - } - case ' ', '\t', '\n', '\r', '&', '>', '<', '|', ';', '(', ')': - tok = _LitWord - break loop - case '?', '*', '+', '@', '!': - if p.bash() && i+1 < len(p.src) && p.src[i+1] == '(' { - break loop - } - case '`': - if p.quote == subCmdBckquo { - tok = _LitWord - } - break loop - case '"', '\'', '$': - break loop - case '=': - p.asPos = i - p.npos - if p.bash() && p.asPos > 0 && p.src[p.npos+p.asPos-1] == '+' { - p.asPos-- // a+=b - } - } - } - if i == len(p.src) { - tok = _LitWord - } - p.tok, p.val = tok, string(p.src[p.npos:i]) - p.npos = i -} - -func (p *parser) advanceLitNoneCont(bs []byte) { - for { - if p.npos >= len(p.src) { - p.tok, p.val = _LitWord, string(bs) - return - } - switch p.src[p.npos] { - case '\\': // escaped byte follows - if p.npos == len(p.src)-1 { - p.npos++ - bs = append(bs, '\\') - p.tok, p.val = _LitWord, string(bs) - return - } - b := p.src[p.npos+1] - p.npos += 2 - if b == '\n' { - p.f.Lines = append(p.f.Lines, p.npos) - } else { - bs = append(bs, '\\', b) - } - case ' ', '\t', '\n', '\r', '&', '>', '<', '|', ';', '(', ')': - p.tok, p.val = _LitWord, string(bs) - return - case '`': - if p.quote == subCmdBckquo { - p.tok, p.val = _LitWord, string(bs) - return - } - fallthrough - case '"', '\'', '$': - p.tok, p.val = _Lit, string(bs) - return - default: - bs = append(bs, p.src[p.npos]) - p.npos++ - } - } -} - -func (p *parser) advanceLitDquote() { - var i int - tok := _Lit -loop: - for i = p.npos; i < len(p.src); i++ { - switch p.src[i] { - case '\\': // escaped byte follows - if i == len(p.src)-1 { - break - } - if i++; p.src[i] == '\n' { - p.f.Lines = append(p.f.Lines, i+1) - } - case '"': - tok = _LitWord - break loop - case '`', '$': - break loop - case '\n': - p.f.Lines = append(p.f.Lines, i+1) - } - } - p.tok, p.val = tok, string(p.src[p.npos:i]) - p.npos = i -} - -func (p *parser) isHdocEnd(i int) bool { - end := p.hdocStop - if end == nil || len(p.src) < i+len(end) { - return false - } - if !bytes.Equal(end, p.src[i:i+len(end)]) { - return false - } - return len(p.src) == i+len(end) || p.src[i+len(end)] == '\n' -} - -func (p *parser) advanceLitHdoc() { - n := p.npos - if p.quote == hdocBodyTabs { - for n < len(p.src) && p.src[n] == '\t' { - n++ - } - } - if p.isHdocEnd(n) { - if n > p.npos { - p.tok, p.val = _LitWord, string(p.src[p.npos:n]) - } - p.npos = n + len(p.hdocStop) - p.hdocStop = nil - return - } - var i int -loop: - for i = p.npos; i < len(p.src); i++ { - switch p.src[i] { - case '\\': // escaped byte follows - if i++; i == len(p.src) { - break loop - } - if p.src[i] == '\n' { - p.f.Lines = append(p.f.Lines, i+1) - } - case '`', '$': - break loop - case '\n': - n := i + 1 - p.f.Lines = append(p.f.Lines, n) - if p.quote == hdocBodyTabs { - for n < len(p.src) && p.src[n] == '\t' { - n++ - } - } - if p.isHdocEnd(n) { - p.tok, p.val = _LitWord, string(p.src[p.npos:n]) - p.npos = n + len(p.hdocStop) - p.hdocStop = nil - return - } - } - } - p.tok, p.val = _Lit, string(p.src[p.npos:i]) - p.npos = i -} - -func (p *parser) hdocLitWord() Word { - pos := p.npos - end := pos - for p.npos < len(p.src) { - end = p.npos - bs, found := p.readUntil('\n') - p.npos += len(bs) + 1 - if found { - p.f.Lines = append(p.f.Lines, p.npos) - } - if p.quote == hdocBodyTabs { - for end < len(p.src) && p.src[end] == '\t' { - end++ - } - } - if p.isHdocEnd(end) { - break - } - } - if p.npos == len(p.src) { - end = p.npos - } - l := p.lit(Pos(pos+1), string(p.src[pos:end])) - return Word{Parts: p.singleWps(l)} -} - -func (p *parser) readUntil(b byte) ([]byte, bool) { - rem := p.src[p.npos:] - if i := bytes.IndexByte(rem, b); i >= 0 { - return rem[:i], true - } - return rem, false -} - -func (p *parser) advanceLitRe() { - end := bytes.Index(p.src[p.npos:], []byte(" ]]")) - p.tok = _LitWord - if end == -1 { - p.val = string(p.src[p.npos:]) - p.npos = len(p.src) - return - } - p.val = string(p.src[p.npos : p.npos+end]) - p.npos += end -} - -func testUnaryOp(val string) Token { - switch val { - case "!": - return Not - case "-e", "-a": - return tsExists - case "-f": - return tsRegFile - case "-d": - return tsDirect - case "-c": - return tsCharSp - case "-b": - return tsBlckSp - case "-p": - return tsNmPipe - case "-S": - return tsSocket - case "-L", "-h": - return tsSmbLink - case "-g": - return tsGIDSet - case "-u": - return tsUIDSet - case "-r": - return tsRead - case "-w": - return tsWrite - case "-x": - return tsExec - case "-s": - return tsNoEmpty - case "-t": - return tsFdTerm - case "-z": - return tsEmpStr - case "-n": - return tsNempStr - case "-o": - return tsOptSet - case "-v": - return tsVarSet - case "-R": - return tsRefVar - default: - return illegalTok - } -} - -func testBinaryOp(val string) Token { - switch val { - case "=": - return Assgn - case "==": - return Eql - case "!=": - return Neq - case "=~": - return tsReMatch - case "-nt": - return tsNewer - case "-ot": - return tsOlder - case "-ef": - return tsDevIno - case "-eq": - return tsEql - case "-ne": - return tsNeq - case "-le": - return tsLeq - case "-ge": - return tsGeq - case "-lt": - return tsLss - case "-gt": - return tsGtr - default: - return illegalTok - } -} diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/nodes.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/nodes.go deleted file mode 100644 index 786cafc4b..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/nodes.go +++ /dev/null @@ -1,717 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -// Node represents an AST node. -type Node interface { - // Pos returns the first character of the node - Pos() Pos - // End returns the character immediately after the node - End() Pos -} - -// File is a shell program. -type File struct { - Name string - - Stmts []*Stmt - Comments []*Comment - - // Lines contains the offset of the first character for each - // line (the first entry is always 0) - Lines []int -} - -func (f *File) Pos() Pos { return stmtFirstPos(f.Stmts) } -func (f *File) End() Pos { return stmtLastEnd(f.Stmts) } - -func (f *File) Position(p Pos) (pos Position) { - intp := int(p) - pos.Offset = intp - 1 - if i := searchInts(f.Lines, intp); i >= 0 { - pos.Line, pos.Column = i+1, intp-f.Lines[i] - } - return -} - -// Inlined version of: -// sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 -func searchInts(a []int, x int) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)/2 - if a[h] <= x { - i = h + 1 - } else { - j = h - } - } - return i - 1 -} - -func posMax(p1, p2 Pos) Pos { - if p2 > p1 { - return p2 - } - return p1 -} - -// Comment represents a single comment on a single line. -type Comment struct { - Hash Pos - Text string -} - -func (c *Comment) Pos() Pos { return c.Hash } -func (c *Comment) End() Pos { return posAddStr(c.Hash, c.Text) } - -// Stmt represents a statement, otherwise known as a compound command. -// It is compromised of a command and other components that may come -// before or after it. -type Stmt struct { - Cmd Command - Position Pos - SemiPos Pos - Negated bool - Background bool - Assigns []*Assign - Redirs []*Redirect -} - -func (s *Stmt) Pos() Pos { return s.Position } -func (s *Stmt) End() Pos { - if s.SemiPos > 0 { - return s.SemiPos + 1 - } - end := s.Position - if s.Negated { - end = posAdd(end, 1) - } - if s.Cmd != nil { - end = s.Cmd.End() - } - if len(s.Assigns) > 0 { - assEnd := s.Assigns[len(s.Assigns)-1].End() - end = posMax(end, assEnd) - } - if len(s.Redirs) > 0 { - redEnd := s.Redirs[len(s.Redirs)-1].End() - end = posMax(end, redEnd) - } - return end -} - -// Command represents all nodes that are simple commands, which are -// directly placed in a Stmt. -type Command interface { - Node - commandNode() -} - -func (*CallExpr) commandNode() {} -func (*IfClause) commandNode() {} -func (*WhileClause) commandNode() {} -func (*UntilClause) commandNode() {} -func (*ForClause) commandNode() {} -func (*CaseClause) commandNode() {} -func (*Block) commandNode() {} -func (*Subshell) commandNode() {} -func (*BinaryCmd) commandNode() {} -func (*FuncDecl) commandNode() {} -func (*ArithmCmd) commandNode() {} -func (*TestClause) commandNode() {} -func (*DeclClause) commandNode() {} -func (*EvalClause) commandNode() {} -func (*LetClause) commandNode() {} -func (*CoprocClause) commandNode() {} - -// Assign represents an assignment to a variable. -type Assign struct { - Append bool - Name *Lit - Value Word -} - -func (a *Assign) Pos() Pos { - if a.Name == nil { - return a.Value.Pos() - } - return a.Name.Pos() -} - -func (a *Assign) End() Pos { - if a.Name != nil { - return posMax(a.Name.End(), a.Value.End()) - } - return a.Value.End() -} - -// Redirect represents an input/output redirection. -type Redirect struct { - OpPos Pos - Op RedirOperator - N *Lit - Word, Hdoc Word -} - -func (r *Redirect) Pos() Pos { - if r.N != nil { - return r.N.Pos() - } - return r.OpPos -} -func (r *Redirect) End() Pos { return r.Word.End() } - -// CallExpr represents a command execution or function call. -type CallExpr struct { - Args []Word -} - -func (c *CallExpr) Pos() Pos { return c.Args[0].Pos() } -func (c *CallExpr) End() Pos { return c.Args[len(c.Args)-1].End() } - -// Subshell represents a series of commands that should be executed in a -// nested shell environment. -type Subshell struct { - Lparen, Rparen Pos - Stmts []*Stmt -} - -func (s *Subshell) Pos() Pos { return s.Lparen } -func (s *Subshell) End() Pos { return posAdd(s.Rparen, 1) } - -// Block represents a series of commands that should be executed in a -// nested scope. -type Block struct { - Lbrace, Rbrace Pos - Stmts []*Stmt -} - -func (b *Block) Pos() Pos { return b.Rbrace } -func (b *Block) End() Pos { return posAdd(b.Rbrace, 1) } - -// IfClause represents an if statement. -type IfClause struct { - If, Then, Fi Pos - CondStmts []*Stmt - ThenStmts []*Stmt - Elifs []*Elif - Else Pos - ElseStmts []*Stmt -} - -func (c *IfClause) Pos() Pos { return c.If } -func (c *IfClause) End() Pos { return posAdd(c.Fi, 2) } - -// Elif represents an "else if" case in an if clause. -type Elif struct { - Elif, Then Pos - CondStmts []*Stmt - ThenStmts []*Stmt -} - -// WhileClause represents a while clause. -type WhileClause struct { - While, Do, Done Pos - CondStmts []*Stmt - DoStmts []*Stmt -} - -func (w *WhileClause) Pos() Pos { return w.While } -func (w *WhileClause) End() Pos { return posAdd(w.Done, 4) } - -// UntilClause represents an until clause. -type UntilClause struct { - Until, Do, Done Pos - CondStmts []*Stmt - DoStmts []*Stmt -} - -func (u *UntilClause) Pos() Pos { return u.Until } -func (u *UntilClause) End() Pos { return posAdd(u.Done, 4) } - -// ForClause represents a for clause. -type ForClause struct { - For, Do, Done Pos - Loop Loop - DoStmts []*Stmt -} - -func (f *ForClause) Pos() Pos { return f.For } -func (f *ForClause) End() Pos { return posAdd(f.Done, 4) } - -// Loop represents all nodes that can be loops in a for clause. -type Loop interface { - Node - loopNode() -} - -func (*WordIter) loopNode() {} -func (*CStyleLoop) loopNode() {} - -// WordIter represents the iteration of a variable over a series of -// words in a for clause. -type WordIter struct { - Name Lit - List []Word -} - -func (w *WordIter) Pos() Pos { return w.Name.Pos() } -func (w *WordIter) End() Pos { return posMax(w.Name.End(), wordLastEnd(w.List)) } - -// CStyleLoop represents the behaviour of a for clause similar to the C -// language. -// -// This node will never appear when in PosixConformant mode. -type CStyleLoop struct { - Lparen, Rparen Pos - Init, Cond, Post ArithmExpr -} - -func (c *CStyleLoop) Pos() Pos { return c.Lparen } -func (c *CStyleLoop) End() Pos { return posAdd(c.Rparen, 2) } - -// BinaryCmd represents a binary expression between two statements. -type BinaryCmd struct { - OpPos Pos - Op BinCmdOperator - X, Y *Stmt -} - -func (b *BinaryCmd) Pos() Pos { return b.X.Pos() } -func (b *BinaryCmd) End() Pos { return b.Y.End() } - -// FuncDecl represents the declaration of a function. -type FuncDecl struct { - Position Pos - BashStyle bool - Name Lit - Body *Stmt -} - -func (f *FuncDecl) Pos() Pos { return f.Position } -func (f *FuncDecl) End() Pos { return f.Body.End() } - -// Word represents a list of nodes that are contiguous to each other. -// The word is delimeted by word boundaries. -type Word struct { - Parts []WordPart -} - -func (w *Word) Pos() Pos { return partsFirstPos(w.Parts) } -func (w *Word) End() Pos { return partsLastEnd(w.Parts) } - -// WordPart represents all nodes that can form a word. -type WordPart interface { - Node - wordPartNode() -} - -func (*Lit) wordPartNode() {} -func (*SglQuoted) wordPartNode() {} -func (*DblQuoted) wordPartNode() {} -func (*ParamExp) wordPartNode() {} -func (*CmdSubst) wordPartNode() {} -func (*ArithmExp) wordPartNode() {} -func (*ProcSubst) wordPartNode() {} -func (*ArrayExpr) wordPartNode() {} -func (*ExtGlob) wordPartNode() {} - -// Lit represents an unquoted string consisting of characters that were -// not tokenized. -type Lit struct { - ValuePos Pos - Value string -} - -func (l *Lit) Pos() Pos { return l.ValuePos } -func (l *Lit) End() Pos { return posAddStr(l.ValuePos, l.Value) } - -// SglQuoted represents a string within single quotes. -type SglQuoted struct { - Position Pos - Dollar bool - Value string -} - -func (q *SglQuoted) Pos() Pos { return q.Position } -func (q *SglQuoted) End() Pos { - pos := posAdd(q.Position, 2+len(q.Value)) - if pos > 0 && q.Dollar { - pos++ - } - return pos -} - -// DblQuoted represents a list of nodes within double quotes. -type DblQuoted struct { - Position Pos - Dollar bool - Parts []WordPart -} - -func (q *DblQuoted) Pos() Pos { return q.Position } -func (q *DblQuoted) End() Pos { - if q.Position == 0 { - return defaultPos - } - end := q.Position - if len(q.Parts) > 0 { - end = partsLastEnd(q.Parts) - } else if q.Dollar { - end += 2 - } else { - end++ - } - return posAdd(end, 1) -} - -// CmdSubst represents a command substitution. -type CmdSubst struct { - Left, Right Pos - Stmts []*Stmt -} - -func (c *CmdSubst) Pos() Pos { return c.Left } -func (c *CmdSubst) End() Pos { return posAdd(c.Right, 1) } - -// ParamExp represents a parameter expansion. -type ParamExp struct { - Dollar, Rbrace Pos - Short, Length bool - Param Lit - Ind *Index - Slice *Slice - Repl *Replace - Exp *Expansion -} - -func (p *ParamExp) Pos() Pos { return p.Dollar } -func (p *ParamExp) End() Pos { - if p.Rbrace > 0 { - return p.Rbrace + 1 - } - return p.Param.End() -} - -// Index represents access to an array via an index inside a ParamExp. -// -// This node will never appear when in PosixConformant mode. -type Index struct { - Word Word -} - -// Slice represents character slicing inside a ParamExp. -// -// This node will never appear when in PosixConformant mode. -type Slice struct { - Offset, Length Word -} - -// Replace represents a search and replace inside a ParamExp. -type Replace struct { - All bool - Orig, With Word -} - -// Expansion represents string manipulation in a ParamExp other than -// those covered by Replace. -type Expansion struct { - Op ParExpOperator - Word Word -} - -// ArithmExp represents an arithmetic expansion. -type ArithmExp struct { - Left, Right Pos - Bracket bool - X ArithmExpr -} - -func (a *ArithmExp) Pos() Pos { return a.Left } -func (a *ArithmExp) End() Pos { - if a.Bracket { - return posAdd(a.Right, 1) - } - return posAdd(a.Right, 2) -} - -// ArithmCmd represents an arithmetic command. -// -// This node will never appear when in PosixConformant mode. -type ArithmCmd struct { - Left, Right Pos - X ArithmExpr -} - -func (a *ArithmCmd) Pos() Pos { return a.Left } -func (a *ArithmCmd) End() Pos { return posAdd(a.Right, 2) } - -// ArithmExpr represents all nodes that form arithmetic expressions. -type ArithmExpr interface { - Node - arithmExprNode() -} - -func (*BinaryArithm) arithmExprNode() {} -func (*UnaryArithm) arithmExprNode() {} -func (*ParenArithm) arithmExprNode() {} -func (*Word) arithmExprNode() {} - -// BinaryArithm represents a binary expression between two arithmetic -// expression. -type BinaryArithm struct { - OpPos Pos - Op Token - X, Y ArithmExpr -} - -func (b *BinaryArithm) Pos() Pos { return b.X.Pos() } -func (b *BinaryArithm) End() Pos { return b.Y.End() } - -// UnaryArithm represents an unary expression over a node, either before -// or after it. -type UnaryArithm struct { - OpPos Pos - Op Token - Post bool - X ArithmExpr -} - -func (u *UnaryArithm) Pos() Pos { - if u.Post { - return u.X.Pos() - } - return u.OpPos -} - -func (u *UnaryArithm) End() Pos { - if u.Post { - return posAdd(u.OpPos, 2) - } - return u.X.End() -} - -// ParenArithm represents an expression within parentheses inside an -// ArithmExp. -type ParenArithm struct { - Lparen, Rparen Pos - X ArithmExpr -} - -func (p *ParenArithm) Pos() Pos { return p.Lparen } -func (p *ParenArithm) End() Pos { return posAdd(p.Rparen, 1) } - -// CaseClause represents a case (switch) clause. -type CaseClause struct { - Case, Esac Pos - Word Word - List []*PatternList -} - -func (c *CaseClause) Pos() Pos { return c.Case } -func (c *CaseClause) End() Pos { return posAdd(c.Esac, 4) } - -// PatternList represents a pattern list (case) within a CaseClause. -type PatternList struct { - Op CaseOperator - OpPos Pos - Patterns []Word - Stmts []*Stmt -} - -// TestClause represents a Bash extended test clause. -// -// This node will never appear when in PosixConformant mode. -type TestClause struct { - Left, Right Pos - X TestExpr -} - -func (t *TestClause) Pos() Pos { return t.Left } -func (t *TestClause) End() Pos { return posAdd(t.Right, 2) } - -// TestExpr represents all nodes that form arithmetic expressions. -type TestExpr interface { - Node - testExprNode() -} - -func (*BinaryTest) testExprNode() {} -func (*UnaryTest) testExprNode() {} -func (*ParenTest) testExprNode() {} -func (*Word) testExprNode() {} - -// BinaryTest represents a binary expression between two arithmetic -// expression. -type BinaryTest struct { - OpPos Pos - Op BinTestOperator - X, Y TestExpr -} - -func (b *BinaryTest) Pos() Pos { return b.X.Pos() } -func (b *BinaryTest) End() Pos { return b.Y.End() } - -// UnaryTest represents an unary expression over a node, either before -// or after it. -type UnaryTest struct { - OpPos Pos - Op UnTestOperator - X TestExpr -} - -func (u *UnaryTest) Pos() Pos { return u.OpPos } -func (u *UnaryTest) End() Pos { return u.X.End() } - -// ParenTest represents an expression within parentheses inside an -// TestExp. -type ParenTest struct { - Lparen, Rparen Pos - X TestExpr -} - -func (p *ParenTest) Pos() Pos { return p.Lparen } -func (p *ParenTest) End() Pos { return posAdd(p.Rparen, 1) } - -// DeclClause represents a Bash declare clause. -// -// This node will never appear when in PosixConformant mode. -type DeclClause struct { - Position Pos - Variant string - Opts []Word - Assigns []*Assign -} - -func (d *DeclClause) Pos() Pos { return d.Position } -func (d *DeclClause) End() Pos { - end := wordLastEnd(d.Opts) - if len(d.Assigns) > 0 { - assignEnd := d.Assigns[len(d.Assigns)-1].End() - end = posMax(end, assignEnd) - } - return end -} - -// ArrayExpr represents a Bash array expression. -// -// This node will never appear when in PosixConformant mode. -type ArrayExpr struct { - Lparen, Rparen Pos - List []Word -} - -func (a *ArrayExpr) Pos() Pos { return a.Lparen } -func (a *ArrayExpr) End() Pos { return posAdd(a.Rparen, 1) } - -// ExtGlob represents a Bash extended globbing expression. Note that -// these are parsed independently of whether shopt has been called or -// not. -// -// This node will never appear when in PosixConformant mode. -type ExtGlob struct { - Op GlobOperator - Pattern Lit -} - -func (e *ExtGlob) Pos() Pos { return posAdd(e.Pattern.Pos(), -2) } -func (e *ExtGlob) End() Pos { return posAdd(e.Pattern.End(), 1) } - -// ProcSubst represents a Bash process substitution. -// -// This node will never appear when in PosixConformant mode. -type ProcSubst struct { - OpPos, Rparen Pos - Op ProcOperator - Stmts []*Stmt -} - -func (s *ProcSubst) Pos() Pos { return s.OpPos } -func (s *ProcSubst) End() Pos { return posAdd(s.Rparen, 1) } - -// EvalClause represents a Bash eval clause. -// -// This node will never appear when in PosixConformant mode. -type EvalClause struct { - Eval Pos - Stmt *Stmt -} - -func (e *EvalClause) Pos() Pos { return e.Eval } -func (e *EvalClause) End() Pos { - if e.Stmt == nil { - return posAdd(e.Eval, 4) - } - return e.Stmt.End() -} - -// CoprocClause represents a Bash coproc clause. -// -// This node will never appear when in PosixConformant mode. -type CoprocClause struct { - Coproc Pos - Name *Lit - Stmt *Stmt -} - -func (c *CoprocClause) Pos() Pos { return c.Coproc } -func (c *CoprocClause) End() Pos { return c.Stmt.End() } - -// LetClause represents a Bash let clause. -// -// This node will never appear when in PosixConformant mode. -type LetClause struct { - Let Pos - Exprs []ArithmExpr -} - -func (l *LetClause) Pos() Pos { return l.Let } -func (l *LetClause) End() Pos { return l.Exprs[len(l.Exprs)-1].End() } - -func posAdd(pos Pos, n int) Pos { - if pos == defaultPos { - return pos - } - return pos + Pos(n) -} - -func posAddStr(pos Pos, s string) Pos { - return posAdd(pos, len(s)) -} - -func stmtFirstPos(sts []*Stmt) Pos { - if len(sts) == 0 { - return defaultPos - } - return sts[0].Pos() -} - -func stmtLastEnd(sts []*Stmt) Pos { - if len(sts) == 0 { - return defaultPos - } - return sts[len(sts)-1].End() -} - -func partsFirstPos(ps []WordPart) Pos { - if len(ps) == 0 { - return defaultPos - } - return ps[0].Pos() -} - -func partsLastEnd(ps []WordPart) Pos { - if len(ps) == 0 { - return defaultPos - } - return ps[len(ps)-1].End() -} - -func wordLastEnd(ws []Word) Pos { - if len(ws) == 0 { - return defaultPos - } - return ws[len(ws)-1].End() -} diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/parser.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/parser.go deleted file mode 100644 index c9ef38eab..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/parser.go +++ /dev/null @@ -1,1659 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -import ( - "bytes" - "fmt" - "strconv" - "sync" -) - -// ParseMode controls the parser behaviour via a set of flags. -type ParseMode uint - -const ( - ParseComments ParseMode = 1 << iota // add comments to the AST - PosixConformant // match the POSIX standard where it differs from bash -) - -var parserFree = sync.Pool{ - New: func() interface{} { - return &parser{helperBuf: new(bytes.Buffer)} - }, -} - -// Parse reads and parses a shell program with an optional name. It -// returns the parsed program if no issues were encountered. Otherwise, -// an error is returned. -func Parse(src []byte, name string, mode ParseMode) (*File, error) { - p := parserFree.Get().(*parser) - p.reset() - alloc := &struct { - f File - l [16]int - }{} - p.f = &alloc.f - p.f.Name = name - p.f.Lines = alloc.l[:1] - p.src, p.mode = src, mode - p.next() - p.f.Stmts = p.stmts() - parserFree.Put(p) - return p.f, p.err -} - -type parser struct { - src []byte - - f *File - mode ParseMode - - spaced, newLine bool - - err error - - tok Token - val string - - pos Pos - npos int - - quote quoteState - asPos int - - // list of pending heredoc bodies - buriedHdocs int - heredocs []*Redirect - hdocStop []byte - - helperBuf *bytes.Buffer - - litBatch []Lit - wpsBatch []WordPart - stmtBatch []Stmt - stListBatch []*Stmt - - litBuf [32]byte -} - -func (p *parser) lit(pos Pos, val string) *Lit { - if len(p.litBatch) == 0 { - p.litBatch = make([]Lit, 32) - } - l := &p.litBatch[0] - l.ValuePos = pos - l.Value = val - p.litBatch = p.litBatch[1:] - return l -} - -func (p *parser) singleWps(wp WordPart) []WordPart { - if len(p.wpsBatch) == 0 { - p.wpsBatch = make([]WordPart, 64) - } - wps := p.wpsBatch[:1:1] - p.wpsBatch = p.wpsBatch[1:] - wps[0] = wp - return wps -} - -func (p *parser) wps() []WordPart { - if len(p.wpsBatch) < 4 { - p.wpsBatch = make([]WordPart, 64) - } - wps := p.wpsBatch[:0:4] - p.wpsBatch = p.wpsBatch[4:] - return wps -} - -func (p *parser) stmt(pos Pos) *Stmt { - if len(p.stmtBatch) == 0 { - p.stmtBatch = make([]Stmt, 16) - } - s := &p.stmtBatch[0] - s.Position = pos - p.stmtBatch = p.stmtBatch[1:] - return s -} - -func (p *parser) stList() []*Stmt { - if len(p.stListBatch) == 0 { - p.stListBatch = make([]*Stmt, 128) - } - stmts := p.stListBatch[:0:4] - p.stListBatch = p.stListBatch[4:] - return stmts -} - -type quoteState int - -const ( - noState quoteState = 1 << iota - subCmd - subCmdBckquo - sglQuotes - dblQuotes - hdocWord - hdocBody - hdocBodyTabs - arithmExpr - arithmExprLet - arithmExprCmd - arithmExprBrack - testRegexp - switchCase - paramExpName - paramExpInd - paramExpRepl - paramExpExp - - allRegTokens = noState | subCmd | subCmdBckquo | hdocWord | switchCase - allArithmExpr = arithmExpr | arithmExprLet | arithmExprCmd | arithmExprBrack - allRbrack = arithmExprBrack | paramExpInd -) - -func (p *parser) bash() bool { return p.mode&PosixConformant == 0 } - -func (p *parser) reset() { - p.spaced, p.newLine = false, false - p.err = nil - p.npos = 0 - p.tok, p.quote = illegalTok, noState - p.heredocs = p.heredocs[:0] - p.buriedHdocs = 0 -} - -type saveState struct { - quote quoteState - buriedHdocs int -} - -func (p *parser) preNested(quote quoteState) (s saveState) { - s.quote = p.quote - s.buriedHdocs = p.buriedHdocs - p.buriedHdocs = len(p.heredocs) - p.quote = quote - return -} - -func (p *parser) postNested(s saveState) { - p.quote, p.buriedHdocs = s.quote, s.buriedHdocs -} - -func (p *parser) unquotedWordBytes(w Word) ([]byte, bool) { - p.helperBuf.Reset() - didUnquote := false - for _, wp := range w.Parts { - if p.unquotedWordPart(p.helperBuf, wp) { - didUnquote = true - } - } - return p.helperBuf.Bytes(), didUnquote -} - -func (p *parser) unquotedWordPart(b *bytes.Buffer, wp WordPart) bool { - switch x := wp.(type) { - case *Lit: - if x.Value[0] == '\\' { - b.WriteString(x.Value[1:]) - return true - } - b.WriteString(x.Value) - return false - case *SglQuoted: - b.WriteString(x.Value) - return true - case *DblQuoted: - for _, wp2 := range x.Parts { - p.unquotedWordPart(b, wp2) - } - return true - default: - // catch-all for unusual cases such as ParamExp - b.Write(p.src[wp.Pos()-1 : wp.End()-1]) - return false - } -} - -func (p *parser) doHeredocs() { - p.tok = illegalTok - old := p.quote - hdocs := p.heredocs[p.buriedHdocs:] - p.heredocs = p.heredocs[:p.buriedHdocs] - for i, r := range hdocs { - if r.Op == DashHdoc { - p.quote = hdocBodyTabs - } else { - p.quote = hdocBody - } - var quoted bool - p.hdocStop, quoted = p.unquotedWordBytes(r.Word) - if i > 0 && p.npos < len(p.src) && p.src[p.npos] == '\n' { - p.npos++ - p.f.Lines = append(p.f.Lines, p.npos) - } - if !quoted { - p.next() - r.Hdoc = p.word() - continue - } - r.Hdoc = p.hdocLitWord() - - } - p.quote = old -} - -func (p *parser) got(tok Token) bool { - if p.tok == tok { - p.next() - return true - } - return false -} - -func (p *parser) gotRsrv(val string) bool { - if p.tok == _LitWord && p.val == val { - p.next() - return true - } - return false -} - -func (p *parser) gotSameLine(tok Token) bool { - if !p.newLine && p.tok == tok { - p.next() - return true - } - return false -} - -func readableStr(s string) string { - // don't quote tokens like & or } - if s != "" && s[0] >= 'a' && s[0] <= 'z' { - return strconv.Quote(s) - } - return s -} - -func (p *parser) followErr(pos Pos, left, right string) { - leftStr := readableStr(left) - p.posErr(pos, "%s must be followed by %s", leftStr, right) -} - -func (p *parser) follow(lpos Pos, left string, tok Token) Pos { - pos := p.pos - if !p.got(tok) { - p.followErr(lpos, left, tok.String()) - } - return pos -} - -func (p *parser) followRsrv(lpos Pos, left, val string) Pos { - pos := p.pos - if !p.gotRsrv(val) { - p.followErr(lpos, left, fmt.Sprintf("%q", val)) - } - return pos -} - -func (p *parser) followStmts(left string, lpos Pos, stops ...string) []*Stmt { - if p.gotSameLine(semicolon) { - return nil - } - sts := p.stmts(stops...) - if len(sts) < 1 && !p.newLine { - p.followErr(lpos, left, "a statement list") - } - return sts -} - -func (p *parser) followWordTok(tok Token, pos Pos) Word { - w := p.word() - if w.Parts == nil { - p.followErr(pos, tok.String(), "a word") - } - return w -} - -func (p *parser) followWord(s string, pos Pos) Word { - w := p.word() - if w.Parts == nil { - p.followErr(pos, s, "a word") - } - return w -} - -func (p *parser) stmtEnd(n Node, start, end string) Pos { - pos := p.pos - if !p.gotRsrv(end) { - p.posErr(n.Pos(), "%s statement must end with %q", start, end) - } - return pos -} - -func (p *parser) quoteErr(lpos Pos, quote Token) { - p.posErr(lpos, "reached %s without closing quote %s", p.tok, quote) -} - -func (p *parser) matchingErr(lpos Pos, left, right interface{}) { - p.posErr(lpos, "reached %s without matching %s with %s", p.tok, left, right) -} - -func (p *parser) matched(lpos Pos, left, right Token) Pos { - pos := p.pos - if !p.got(right) { - p.matchingErr(lpos, left, right) - } - return pos -} - -func (p *parser) errPass(err error) { - if p.err == nil { - p.err = err - p.tok = _EOF - } -} - -// ParseError represents an error found when parsing a source file. -type ParseError struct { - Position - Filename, Text string -} - -func (e *ParseError) Error() string { - prefix := "" - if e.Filename != "" { - prefix = e.Filename + ":" - } - return fmt.Sprintf("%s%d:%d: %s", prefix, e.Line, e.Column, e.Text) -} - -func (p *parser) posErr(pos Pos, format string, a ...interface{}) { - p.errPass(&ParseError{ - Position: p.f.Position(pos), - Filename: p.f.Name, - Text: fmt.Sprintf(format, a...), - }) -} - -func (p *parser) curErr(format string, a ...interface{}) { - p.posErr(p.pos, format, a...) -} - -func (p *parser) stmts(stops ...string) (sts []*Stmt) { - q := p.quote - gotEnd := true - for p.tok != _EOF { - switch p.tok { - case _LitWord: - for _, stop := range stops { - if p.val == stop { - return - } - } - case rightParen: - if q == subCmd { - return - } - case bckQuote: - if q == subCmdBckquo { - return - } - case dblSemicolon, semiFall, dblSemiFall: - if q == switchCase { - return - } - p.curErr("%s can only be used in a case clause", p.tok) - } - if !p.newLine && !gotEnd { - p.curErr("statements must be separated by &, ; or a newline") - } - if p.tok == _EOF { - break - } - if s, end := p.getStmt(true); s == nil { - p.invalidStmtStart() - } else { - if sts == nil { - sts = p.stList() - } - sts = append(sts, s) - gotEnd = end - } - } - return -} - -func (p *parser) invalidStmtStart() { - switch p.tok { - case semicolon, And, Or, AndExpr, OrExpr: - p.curErr("%s can only immediately follow a statement", p.tok) - case rightParen: - p.curErr("%s can only be used to close a subshell", p.tok) - default: - p.curErr("%s is not a valid start for a statement", p.tok) - } -} - -func (p *parser) word() Word { - if p.tok == _LitWord { - w := Word{Parts: p.singleWps(p.lit(p.pos, p.val))} - p.next() - return w - } - return Word{Parts: p.wordParts()} -} - -func (p *parser) gotLit(l *Lit) bool { - l.ValuePos = p.pos - if p.tok == _Lit || p.tok == _LitWord { - l.Value = p.val - p.next() - return true - } - return false -} - -func (p *parser) wordParts() (wps []WordPart) { - for { - n := p.wordPart() - if n == nil { - return - } - if wps == nil { - wps = p.wps() - } - wps = append(wps, n) - if p.spaced { - return - } - } -} - -func (p *parser) wordPart() WordPart { - switch p.tok { - case _Lit, _LitWord: - l := p.lit(p.pos, p.val) - p.next() - return l - case dollBrace: - return p.paramExp() - case dollDblParen, dollBrack: - left := p.tok - ar := &ArithmExp{Left: p.pos, Bracket: left == dollBrack} - old := p.preNested(arithmExpr) - if ar.Bracket { - p.quote = arithmExprBrack - } else if !p.couldBeArithm() { - p.postNested(old) - p.npos = int(ar.Left) + 1 - p.tok = dollParen - p.pos = ar.Left - wp := p.wordPart() - if p.err != nil { - p.err = nil - p.matchingErr(ar.Left, dollDblParen, dblRightParen) - } - return wp - } - p.next() - ar.X = p.arithmExpr(left, ar.Left, 0, false) - if ar.Bracket { - if p.tok != rightBrack { - p.matchingErr(ar.Left, dollBrack, rightBrack) - } - p.postNested(old) - ar.Right = p.pos - p.next() - } else { - ar.Right = p.arithmEnd(dollDblParen, ar.Left, old) - } - return ar - case dollParen: - if p.quote == hdocWord { - p.curErr("nested statements not allowed in heredoc words") - } - cs := &CmdSubst{Left: p.pos} - old := p.preNested(subCmd) - p.next() - cs.Stmts = p.stmts() - p.postNested(old) - cs.Right = p.matched(cs.Left, leftParen, rightParen) - return cs - case dollar: - var b byte - if p.npos >= len(p.src) { - p.tok = _EOF - } else { - b = p.src[p.npos] - } - if p.tok == _EOF || wordBreak(b) || b == '"' || b == '\'' || b == '`' || b == '[' { - l := p.lit(p.pos, "$") - p.next() - return l - } - pe := &ParamExp{Dollar: p.pos, Short: true} - p.pos++ - switch b { - case '@', '*', '#', '$', '?', '!', '0', '-': - p.npos++ - p.tok, p.val = _Lit, string(b) - default: - p.advanceLitOther(p.quote) - } - p.gotLit(&pe.Param) - return pe - case cmdIn, cmdOut: - ps := &ProcSubst{Op: ProcOperator(p.tok), OpPos: p.pos} - old := p.preNested(subCmd) - p.next() - ps.Stmts = p.stmts() - p.postNested(old) - ps.Rparen = p.matched(ps.OpPos, Token(ps.Op), rightParen) - return ps - case sglQuote: - sq := &SglQuoted{Position: p.pos} - bs, found := p.readUntil('\'') - rem := bs - for { - i := bytes.IndexByte(rem, '\n') - if i < 0 { - p.npos += len(rem) - break - } - p.npos += i + 1 - p.f.Lines = append(p.f.Lines, p.npos) - rem = rem[i+1:] - } - p.npos++ - if !found { - p.posErr(sq.Pos(), "reached EOF without closing quote %s", sglQuote) - } - sq.Value = string(bs) - p.next() - return sq - case dollSglQuote: - sq := &SglQuoted{Position: p.pos, Dollar: true} - old := p.quote - p.quote = sglQuotes - p.next() - if p.tok == sglQuote { - p.quote = old - } else { - sq.Value = p.val - p.quote = old - p.next() - } - if !p.got(sglQuote) { - p.quoteErr(sq.Pos(), sglQuote) - } - return sq - case dblQuote: - if p.quote == dblQuotes { - return nil - } - fallthrough - case dollDblQuote: - q := &DblQuoted{Position: p.pos, Dollar: p.tok == dollDblQuote} - old := p.quote - p.quote = dblQuotes - p.next() - if p.tok == _LitWord { - q.Parts = p.singleWps(p.lit(p.pos, p.val)) - p.next() - } else { - q.Parts = p.wordParts() - } - p.quote = old - if !p.got(dblQuote) { - p.quoteErr(q.Pos(), dblQuote) - } - return q - case bckQuote: - switch p.quote { - case hdocWord: - p.curErr("nested statements not allowed in heredoc words") - case subCmdBckquo: - return nil - } - cs := &CmdSubst{Left: p.pos} - old := p.preNested(subCmdBckquo) - p.next() - cs.Stmts = p.stmts() - p.postNested(old) - cs.Right = p.pos - if !p.got(bckQuote) { - p.quoteErr(cs.Pos(), bckQuote) - } - return cs - case globQuest, globMul, globAdd, globAt, globNot: - eg := &ExtGlob{Op: GlobOperator(p.tok)} - eg.Pattern.ValuePos = Pos(p.npos + 1) - start := p.npos - lparens := 0 - for _, b := range p.src[start:] { - p.npos++ - if b == '(' { - lparens++ - } else if b == ')' { - if lparens--; lparens < 0 { - eg.Pattern.Value = string(p.src[start : p.npos-1]) - break - } - } - } - p.next() - if lparens != -1 { - p.matchingErr(p.pos, eg.Op, rightParen) - } - return eg - } - return nil -} - -func (p *parser) couldBeArithm() (could bool) { - // save state - oldTok := p.tok - oldNpos := p.npos - oldLines := len(p.f.Lines) - p.next() - lparens := 0 -tokLoop: - for p.tok != _EOF { - switch p.tok { - case leftParen, dollParen: - lparens++ - case dollDblParen, dblLeftParen: - lparens += 2 - case rightParen: - if lparens == 0 { - could = p.peekArithmEnd() - break tokLoop - } - lparens-- - } - p.next() - } - // recover state - p.tok = oldTok - p.npos = oldNpos - p.f.Lines = p.f.Lines[:oldLines] - return -} - -func arithmOpLevel(tok Token) int { - switch tok { - case Comma: - return 0 - case AddAssgn, SubAssgn, MulAssgn, QuoAssgn, RemAssgn, AndAssgn, - OrAssgn, XorAssgn, ShlAssgn, ShrAssgn: - return 1 - case Assgn: - return 2 - case Quest, Colon: - return 3 - case AndExpr, OrExpr: - return 4 - case And, Or, Xor: - return 5 - case Eql, Neq: - return 6 - case Lss, Gtr, Leq, Geq: - return 7 - case Shl, Shr: - return 8 - case Add, Sub: - return 9 - case Mul, Quo, Rem: - return 10 - case Pow: - return 11 - } - return -1 -} - -func (p *parser) arithmExpr(ftok Token, fpos Pos, level int, compact bool) ArithmExpr { - if p.tok == _EOF || p.peekArithmEnd() { - return nil - } - var left ArithmExpr - if level > 11 { - left = p.arithmExprBase(ftok, fpos, compact) - } else { - left = p.arithmExpr(ftok, fpos, level+1, compact) - } - if compact && p.spaced { - return left - } - newLevel := arithmOpLevel(p.tok) - if newLevel < 0 { - switch p.tok { - case _Lit, _LitWord: - p.curErr("not a valid arithmetic operator: %s", p.val) - return nil - case rightParen, _EOF: - default: - if p.quote == arithmExpr { - p.curErr("not a valid arithmetic operator: %v", p.tok) - return nil - } - } - } - if newLevel < 0 || newLevel < level { - return left - } - b := &BinaryArithm{ - OpPos: p.pos, - Op: p.tok, - X: left, - } - if p.next(); compact && p.spaced { - p.followErr(b.OpPos, b.Op.String(), "an expression") - } - if b.Y = p.arithmExpr(b.Op, b.OpPos, newLevel, compact); b.Y == nil { - p.followErr(b.OpPos, b.Op.String(), "an expression") - } - return b -} - -func (p *parser) arithmExprBase(ftok Token, fpos Pos, compact bool) ArithmExpr { - var x ArithmExpr - switch p.tok { - case Inc, Dec, Not: - pre := &UnaryArithm{OpPos: p.pos, Op: p.tok} - p.next() - pre.X = p.arithmExprBase(pre.Op, pre.OpPos, compact) - return pre - case leftParen: - pe := &ParenArithm{Lparen: p.pos} - p.next() - if pe.X = p.arithmExpr(leftParen, pe.Lparen, 0, false); pe.X == nil { - p.posErr(pe.Lparen, "parentheses must enclose an expression") - } - pe.Rparen = p.matched(pe.Lparen, leftParen, rightParen) - x = pe - case Add, Sub: - ue := &UnaryArithm{OpPos: p.pos, Op: p.tok} - if p.next(); compact && p.spaced { - p.followErr(ue.OpPos, ue.Op.String(), "an expression") - } - if ue.X = p.arithmExpr(ue.Op, ue.OpPos, 0, compact); ue.X == nil { - p.followErr(ue.OpPos, ue.Op.String(), "an expression") - } - x = ue - case bckQuote: - if p.quote == arithmExprLet { - return nil - } - fallthrough - default: - w := p.word() - if w.Parts == nil { - p.followErr(fpos, ftok.String(), "an expression") - } - x = &w - } - if compact && p.spaced { - return x - } - if p.tok == Inc || p.tok == Dec { - u := &UnaryArithm{ - Post: true, - OpPos: p.pos, - Op: p.tok, - X: x, - } - p.next() - return u - } - return x -} - -func (p *parser) gotParamLit(l *Lit) bool { - l.ValuePos = p.pos - switch p.tok { - case _Lit, _LitWord: - l.Value = p.val - case dollar: - l.Value = "$" - case Quest: - l.Value = "?" - case Hash: - l.Value = "#" - case Sub: - l.Value = "-" - default: - return false - } - p.next() - return true -} - -func (p *parser) paramExp() *ParamExp { - pe := &ParamExp{Dollar: p.pos} - old := p.preNested(paramExpName) - p.next() - switch p.tok { - case dblHash: - p.tok = Hash - p.npos-- - fallthrough - case Hash: - if p.npos < len(p.src) && p.src[p.npos] != '}' { - pe.Length = true - p.next() - } - } - if !p.gotParamLit(&pe.Param) && !pe.Length { - p.posErr(pe.Dollar, "parameter expansion requires a literal") - } - if p.tok == rightBrace { - pe.Rbrace = p.pos - p.postNested(old) - p.next() - return pe - } - if p.tok == leftBrack { - if !p.bash() { - p.curErr("arrays are a bash feature") - } - lpos := p.pos - p.quote = paramExpInd - p.next() - pe.Ind = &Index{Word: p.word()} - p.quote = paramExpName - p.matched(lpos, leftBrack, rightBrack) - } - switch p.tok { - case rightBrace: - pe.Rbrace = p.pos - p.postNested(old) - p.next() - return pe - case Quo, dblQuo: - pe.Repl = &Replace{All: p.tok == dblQuo} - p.quote = paramExpRepl - p.next() - pe.Repl.Orig = p.word() - if p.tok == Quo { - p.quote = paramExpExp - p.next() - pe.Repl.With = p.word() - } - case Colon: - if !p.bash() { - p.curErr("slicing is a bash feature") - } - pe.Slice = &Slice{} - colonPos := p.pos - p.next() - if p.tok != Colon { - pe.Slice.Offset = p.followWordTok(Colon, colonPos) - } - colonPos = p.pos - if p.got(Colon) { - pe.Slice.Length = p.followWordTok(Colon, colonPos) - } - case Xor, dblXor, Comma, dblComma: - if !p.bash() { - p.curErr("case expansions are a bash feature") - } - fallthrough - default: - pe.Exp = &Expansion{Op: ParExpOperator(p.tok)} - p.quote = paramExpExp - p.next() - pe.Exp.Word = p.word() - } - p.postNested(old) - pe.Rbrace = p.pos - p.matched(pe.Dollar, dollBrace, rightBrace) - return pe -} - -func (p *parser) peekArithmEnd() bool { - return p.tok == rightParen && p.npos < len(p.src) && p.src[p.npos] == ')' -} - -func (p *parser) arithmEnd(ltok Token, lpos Pos, old saveState) Pos { - if p.peekArithmEnd() { - p.npos++ - } else { - p.matchingErr(lpos, ltok, dblRightParen) - } - p.postNested(old) - pos := p.pos - p.next() - return pos -} - -func stopToken(tok Token) bool { - switch tok { - case _EOF, semicolon, And, Or, AndExpr, OrExpr, pipeAll, dblSemicolon, - semiFall, dblSemiFall, rightParen: - return true - } - return false -} - -func (p *parser) validIdent() bool { - if p.asPos <= 0 { - return false - } - s := p.val[:p.asPos] - for i, c := range s { - switch { - case 'a' <= c && c <= 'z': - case 'A' <= c && c <= 'Z': - case c == '_': - case i > 0 && '0' <= c && c <= '9': - case i > 0 && (c == '[' || c == ']') && p.bash(): - default: - return false - } - } - return true -} - -func (p *parser) getAssign() *Assign { - asPos := p.asPos - as := &Assign{Name: p.lit(p.pos, p.val[:asPos])} - if p.val[asPos] == '+' { - as.Append = true - asPos++ - } - start := p.lit(p.pos+1, p.val[asPos+1:]) - if start.Value != "" { - start.ValuePos += Pos(asPos) - as.Value.Parts = p.singleWps(start) - } - p.next() - if p.spaced { - return as - } - if start.Value == "" && p.tok == leftParen { - if !p.bash() { - p.curErr("arrays are a bash feature") - } - ae := &ArrayExpr{Lparen: p.pos} - p.next() - for p.tok != _EOF && p.tok != rightParen { - if w := p.word(); w.Parts == nil { - p.curErr("array elements must be words") - } else { - ae.List = append(ae.List, w) - } - } - ae.Rparen = p.matched(ae.Lparen, leftParen, rightParen) - as.Value.Parts = p.singleWps(ae) - } else if !p.newLine && !stopToken(p.tok) { - if w := p.word(); start.Value == "" { - as.Value = w - } else { - as.Value.Parts = append(as.Value.Parts, w.Parts...) - } - } - return as -} - -func litRedir(src []byte, npos int) bool { - return npos < len(src) && (src[npos] == '>' || src[npos] == '<') -} - -func (p *parser) peekRedir() bool { - switch p.tok { - case _LitWord: - return litRedir(p.src, p.npos) - case Gtr, Shr, Lss, dplIn, dplOut, clbOut, rdrInOut, Shl, dashHdoc, - wordHdoc, rdrAll, appAll: - return true - } - return false -} - -func (p *parser) doRedirect(s *Stmt) { - r := &Redirect{} - var l Lit - if p.gotLit(&l) { - r.N = &l - } - r.Op, r.OpPos = RedirOperator(p.tok), p.pos - p.next() - switch r.Op { - case Hdoc, DashHdoc: - old := p.quote - p.quote = hdocWord - if p.newLine { - p.curErr("heredoc stop word must be on the same line") - } - p.heredocs = append(p.heredocs, r) - r.Word = p.followWordTok(Token(r.Op), r.OpPos) - p.quote = old - p.next() - default: - if p.newLine { - p.curErr("redirect word must be on the same line") - } - r.Word = p.followWordTok(Token(r.Op), r.OpPos) - } - s.Redirs = append(s.Redirs, r) -} - -func (p *parser) getStmt(readEnd bool) (s *Stmt, gotEnd bool) { - s = p.stmt(p.pos) - if p.gotRsrv("!") { - s.Negated = true - } -preLoop: - for { - switch p.tok { - case _Lit, _LitWord: - if p.validIdent() { - s.Assigns = append(s.Assigns, p.getAssign()) - } else if litRedir(p.src, p.npos) { - p.doRedirect(s) - } else { - break preLoop - } - case Gtr, Shr, Lss, dplIn, dplOut, clbOut, rdrInOut, Shl, dashHdoc, - wordHdoc, rdrAll, appAll: - p.doRedirect(s) - default: - break preLoop - } - switch { - case p.newLine, p.tok == _EOF: - return - case p.tok == semicolon: - if readEnd { - s.SemiPos = p.pos - p.next() - gotEnd = true - } - return - } - } - if s = p.gotStmtPipe(s); s == nil { - return - } - switch p.tok { - case AndExpr, OrExpr: - b := &BinaryCmd{OpPos: p.pos, Op: BinCmdOperator(p.tok), X: s} - p.next() - if b.Y, _ = p.getStmt(false); b.Y == nil { - p.followErr(b.OpPos, b.Op.String(), "a statement") - } - s = p.stmt(s.Position) - s.Cmd = b - if readEnd && p.gotSameLine(semicolon) { - gotEnd = true - } - case And: - p.next() - s.Background = true - gotEnd = true - case semicolon: - if !p.newLine && readEnd { - s.SemiPos = p.pos - p.next() - gotEnd = true - } - } - return -} - -func bashDeclareWord(s string) bool { - switch s { - case "declare", "local", "export", "readonly", "typeset", "nameref": - return true - } - return false -} - -func (p *parser) gotStmtPipe(s *Stmt) *Stmt { - switch p.tok { - case leftParen: - s.Cmd = p.subshell() - case dblLeftParen: - s.Cmd = p.arithmExpCmd() - case _LitWord: - switch { - case p.val == "}": - p.curErr("%s can only be used to close a block", p.val) - case p.val == "{": - s.Cmd = p.block() - case p.val == "if": - s.Cmd = p.ifClause() - case p.val == "while": - s.Cmd = p.whileClause() - case p.val == "until": - s.Cmd = p.untilClause() - case p.val == "for": - s.Cmd = p.forClause() - case p.val == "case": - s.Cmd = p.caseClause() - case p.bash() && p.val == "[[": - s.Cmd = p.testClause() - case p.bash() && bashDeclareWord(p.val): - s.Cmd = p.declClause() - case p.bash() && p.val == "eval": - s.Cmd = p.evalClause() - case p.bash() && p.val == "coproc": - s.Cmd = p.coprocClause() - case p.bash() && p.val == "let": - s.Cmd = p.letClause() - case p.bash() && p.val == "function": - s.Cmd = p.bashFuncDecl() - default: - name := Lit{ValuePos: p.pos, Value: p.val} - p.next() - if p.gotSameLine(leftParen) { - p.follow(name.ValuePos, "foo(", rightParen) - s.Cmd = p.funcDecl(name, name.ValuePos) - } else { - s.Cmd = p.callExpr(s, Word{ - Parts: p.singleWps(&name), - }) - } - } - case _Lit, dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut, sglQuote, - dollSglQuote, dblQuote, dollDblQuote, bckQuote, dollBrack, globQuest, globMul, globAdd, - globAt, globNot: - w := Word{Parts: p.wordParts()} - if p.gotSameLine(leftParen) && p.err == nil { - rawName := string(p.src[w.Pos()-1 : w.End()-1]) - p.posErr(w.Pos(), "invalid func name: %q", rawName) - } - s.Cmd = p.callExpr(s, w) - } - for !p.newLine && p.peekRedir() { - p.doRedirect(s) - } - if s.Cmd == nil && len(s.Redirs) == 0 && !s.Negated && len(s.Assigns) == 0 { - return nil - } - if p.tok == Or || p.tok == pipeAll { - b := &BinaryCmd{OpPos: p.pos, Op: BinCmdOperator(p.tok), X: s} - p.next() - if b.Y = p.gotStmtPipe(p.stmt(p.pos)); b.Y == nil { - p.followErr(b.OpPos, b.Op.String(), "a statement") - } - s = p.stmt(s.Position) - s.Cmd = b - } - return s -} - -func (p *parser) subshell() *Subshell { - s := &Subshell{Lparen: p.pos} - old := p.preNested(subCmd) - p.next() - s.Stmts = p.stmts() - p.postNested(old) - s.Rparen = p.matched(s.Lparen, leftParen, rightParen) - return s -} - -func (p *parser) arithmExpCmd() Command { - ar := &ArithmCmd{Left: p.pos} - old := p.preNested(arithmExprCmd) - if !p.couldBeArithm() { - p.postNested(old) - p.npos = int(ar.Left) - p.tok = leftParen - p.pos = ar.Left - s := p.subshell() - if p.err != nil { - p.err = nil - p.matchingErr(ar.Left, dblLeftParen, dblRightParen) - } - return s - } - p.next() - ar.X = p.arithmExpr(dblLeftParen, ar.Left, 0, false) - ar.Right = p.arithmEnd(dblLeftParen, ar.Left, old) - return ar -} - -func (p *parser) block() *Block { - b := &Block{Lbrace: p.pos} - p.next() - b.Stmts = p.stmts("}") - b.Rbrace = p.pos - if !p.gotRsrv("}") { - p.matchingErr(b.Lbrace, "{", "}") - } - return b -} - -func (p *parser) ifClause() *IfClause { - ic := &IfClause{If: p.pos} - p.next() - ic.CondStmts = p.followStmts("if", ic.If, "then") - ic.Then = p.followRsrv(ic.If, "if ", "then") - ic.ThenStmts = p.followStmts("then", ic.Then, "fi", "elif", "else") - elifPos := p.pos - for p.gotRsrv("elif") { - elf := &Elif{Elif: elifPos} - elf.CondStmts = p.followStmts("elif", elf.Elif, "then") - elf.Then = p.followRsrv(elf.Elif, "elif ", "then") - elf.ThenStmts = p.followStmts("then", elf.Then, "fi", "elif", "else") - ic.Elifs = append(ic.Elifs, elf) - elifPos = p.pos - } - if elsePos := p.pos; p.gotRsrv("else") { - ic.Else = elsePos - ic.ElseStmts = p.followStmts("else", ic.Else, "fi") - } - ic.Fi = p.stmtEnd(ic, "if", "fi") - return ic -} - -func (p *parser) whileClause() *WhileClause { - wc := &WhileClause{While: p.pos} - p.next() - wc.CondStmts = p.followStmts("while", wc.While, "do") - wc.Do = p.followRsrv(wc.While, "while ", "do") - wc.DoStmts = p.followStmts("do", wc.Do, "done") - wc.Done = p.stmtEnd(wc, "while", "done") - return wc -} - -func (p *parser) untilClause() *UntilClause { - uc := &UntilClause{Until: p.pos} - p.next() - uc.CondStmts = p.followStmts("until", uc.Until, "do") - uc.Do = p.followRsrv(uc.Until, "until ", "do") - uc.DoStmts = p.followStmts("do", uc.Do, "done") - uc.Done = p.stmtEnd(uc, "until", "done") - return uc -} - -func (p *parser) forClause() *ForClause { - fc := &ForClause{For: p.pos} - p.next() - fc.Loop = p.loop(fc.For) - fc.Do = p.followRsrv(fc.For, "for foo [in words]", "do") - fc.DoStmts = p.followStmts("do", fc.Do, "done") - fc.Done = p.stmtEnd(fc, "for", "done") - return fc -} - -func (p *parser) loop(forPos Pos) Loop { - if p.tok == dblLeftParen { - cl := &CStyleLoop{Lparen: p.pos} - old := p.preNested(arithmExprCmd) - p.next() - if p.tok == dblSemicolon { - p.npos-- - p.tok = semicolon - } - if p.tok != semicolon { - cl.Init = p.arithmExpr(dblLeftParen, cl.Lparen, 0, false) - } - scPos := p.pos - p.follow(p.pos, "expression", semicolon) - if p.tok != semicolon { - cl.Cond = p.arithmExpr(semicolon, scPos, 0, false) - } - scPos = p.pos - p.follow(p.pos, "expression", semicolon) - if p.tok != semicolon { - cl.Post = p.arithmExpr(semicolon, scPos, 0, false) - } - cl.Rparen = p.arithmEnd(dblLeftParen, cl.Lparen, old) - p.gotSameLine(semicolon) - return cl - } - wi := &WordIter{} - if !p.gotLit(&wi.Name) { - p.followErr(forPos, "for", "a literal") - } - if p.gotRsrv("in") { - for !p.newLine && p.tok != _EOF && p.tok != semicolon { - if w := p.word(); w.Parts == nil { - p.curErr("word list can only contain words") - } else { - wi.List = append(wi.List, w) - } - } - p.gotSameLine(semicolon) - } else if !p.newLine && !p.got(semicolon) { - p.followErr(forPos, "for foo", `"in", ; or a newline`) - } - return wi -} - -func (p *parser) caseClause() *CaseClause { - cc := &CaseClause{Case: p.pos} - p.next() - cc.Word = p.followWord("case", cc.Case) - p.followRsrv(cc.Case, "case x", "in") - cc.List = p.patLists() - cc.Esac = p.stmtEnd(cc, "case", "esac") - return cc -} - -func (p *parser) patLists() (pls []*PatternList) { - for p.tok != _EOF && !(p.tok == _LitWord && p.val == "esac") { - pl := &PatternList{} - p.got(leftParen) - for p.tok != _EOF { - if w := p.word(); w.Parts == nil { - p.curErr("case patterns must consist of words") - } else { - pl.Patterns = append(pl.Patterns, w) - } - if p.tok == rightParen { - break - } - if !p.got(Or) { - p.curErr("case patterns must be separated with |") - } - } - old := p.preNested(switchCase) - p.next() - pl.Stmts = p.stmts("esac") - p.postNested(old) - pl.OpPos = p.pos - if p.tok != dblSemicolon && p.tok != semiFall && p.tok != dblSemiFall { - pl.Op = DblSemicolon - pls = append(pls, pl) - break - } - pl.Op = CaseOperator(p.tok) - p.next() - pls = append(pls, pl) - } - return -} - -func (p *parser) testClause() *TestClause { - tc := &TestClause{Left: p.pos} - p.next() - if p.tok == _EOF || p.gotRsrv("]]") { - p.posErr(tc.Left, "test clause requires at least one expression") - } - tc.X = p.testExpr(illegalTok, tc.Left, 0) - tc.Right = p.pos - if !p.gotRsrv("]]") { - p.matchingErr(tc.Left, "[[", "]]") - } - return tc -} - -func (p *parser) testExpr(ftok Token, fpos Pos, level int) TestExpr { - var left TestExpr - if level > 1 { - left = p.testExprBase(ftok, fpos) - } else { - left = p.testExpr(ftok, fpos, level+1) - } - if left == nil { - return left - } - var newLevel int - switch p.tok { - case AndExpr, OrExpr: - case _LitWord: - if p.val == "]]" { - return left - } - fallthrough - case Lss, Gtr: - newLevel = 1 - case _EOF, rightParen: - return left - default: - p.curErr("not a valid test operator: %v", p.tok) - } - if newLevel < level { - return left - } - if p.tok == _LitWord { - if p.tok = testBinaryOp(p.val); p.tok == illegalTok { - p.curErr("not a valid test operator: %s", p.val) - } - } - b := &BinaryTest{ - OpPos: p.pos, - Op: BinTestOperator(p.tok), - X: left, - } - if b.Op == TsReMatch { - old := p.preNested(testRegexp) - p.next() - p.postNested(old) - } else { - p.next() - } - if b.Y = p.testExpr(Token(b.Op), b.OpPos, newLevel); b.Y == nil { - p.followErr(b.OpPos, b.Op.String(), "an expression") - } - return b -} - -func (p *parser) testExprBase(ftok Token, fpos Pos) TestExpr { - switch p.tok { - case _EOF: - return nil - case _LitWord: - if op := testUnaryOp(p.val); op != illegalTok { - p.tok = op - } - } - switch p.tok { - case Not: - u := &UnaryTest{OpPos: p.pos, Op: TsNot} - p.next() - u.X = p.testExpr(Token(u.Op), u.OpPos, 0) - return u - case tsExists, tsRegFile, tsDirect, tsCharSp, tsBlckSp, tsNmPipe, tsSocket, tsSmbLink, - tsGIDSet, tsUIDSet, tsRead, tsWrite, tsExec, tsNoEmpty, tsFdTerm, tsEmpStr, - tsNempStr, tsOptSet, tsVarSet, tsRefVar: - u := &UnaryTest{OpPos: p.pos, Op: UnTestOperator(p.tok)} - p.next() - w := p.followWordTok(ftok, fpos) - u.X = &w - return u - case leftParen: - pe := &ParenTest{Lparen: p.pos} - p.next() - if pe.X = p.testExpr(leftParen, pe.Lparen, 0); pe.X == nil { - p.posErr(pe.Lparen, "parentheses must enclose an expression") - } - pe.Rparen = p.matched(pe.Lparen, leftParen, rightParen) - return pe - case rightParen: - default: - w := p.followWordTok(ftok, fpos) - return &w - } - return nil -} - -func (p *parser) declClause() *DeclClause { - name := p.val - ds := &DeclClause{Position: p.pos} - switch name { - case "declare", "typeset": // typeset is an obsolete synonym - default: - ds.Variant = name - } - p.next() - for p.tok == _LitWord && p.val[0] == '-' { - ds.Opts = append(ds.Opts, p.word()) - } - for !p.newLine && !stopToken(p.tok) && !p.peekRedir() { - if (p.tok == _Lit || p.tok == _LitWord) && p.validIdent() { - ds.Assigns = append(ds.Assigns, p.getAssign()) - } else if w := p.word(); w.Parts == nil { - p.followErr(p.pos, name, "words") - } else { - ds.Assigns = append(ds.Assigns, &Assign{Value: w}) - } - } - return ds -} - -func (p *parser) evalClause() *EvalClause { - ec := &EvalClause{Eval: p.pos} - p.next() - ec.Stmt, _ = p.getStmt(false) - return ec -} - -func isBashCompoundCommand(tok Token, val string) bool { - switch tok { - case leftParen, dblLeftParen: - return true - case _LitWord: - switch val { - case "{", "if", "while", "until", "for", "case", "[[", "eval", - "coproc", "let", "function": - return true - } - if bashDeclareWord(val) { - return true - } - } - return false -} - -func (p *parser) coprocClause() *CoprocClause { - cc := &CoprocClause{Coproc: p.pos} - p.next() - if isBashCompoundCommand(p.tok, p.val) { - // has no name - cc.Stmt, _ = p.getStmt(false) - return cc - } - if p.newLine { - p.posErr(cc.Coproc, "coproc clause requires a command") - } - var l Lit - if p.gotLit(&l) { - cc.Name = &l - } - cc.Stmt, _ = p.getStmt(false) - if cc.Stmt == nil { - if cc.Name == nil { - p.posErr(cc.Coproc, "coproc clause requires a command") - return nil - } - // name was in fact the stmt - cc.Stmt = &Stmt{ - Position: cc.Name.ValuePos, - Cmd: &CallExpr{Args: []Word{ - {Parts: p.singleWps(cc.Name)}, - }}, - } - cc.Name = nil - } else if cc.Name != nil { - if call, ok := cc.Stmt.Cmd.(*CallExpr); ok { - // name was in fact the start of a call - call.Args = append([]Word{{Parts: p.singleWps(cc.Name)}}, - call.Args...) - cc.Name = nil - } - } - return cc -} - -func (p *parser) letClause() *LetClause { - lc := &LetClause{Let: p.pos} - old := p.preNested(arithmExprLet) - p.next() - for !p.newLine && !stopToken(p.tok) && !p.peekRedir() { - x := p.arithmExpr(illegalTok, lc.Let, 0, true) - if x == nil { - break - } - lc.Exprs = append(lc.Exprs, x) - } - if len(lc.Exprs) == 0 { - p.posErr(lc.Let, "let clause requires at least one expression") - } - p.postNested(old) - if p.tok == illegalTok { - p.next() - } - return lc -} - -func (p *parser) bashFuncDecl() *FuncDecl { - fpos := p.pos - p.next() - if p.tok != _LitWord { - if w := p.followWord("function", fpos); p.err == nil { - rawName := string(p.src[w.Pos()-1 : w.End()-1]) - p.posErr(w.Pos(), "invalid func name: %q", rawName) - } - } - name := Lit{ValuePos: p.pos, Value: p.val} - p.next() - if p.gotSameLine(leftParen) { - p.follow(name.ValuePos, "foo(", rightParen) - } - return p.funcDecl(name, fpos) -} - -func (p *parser) callExpr(s *Stmt, w Word) *CallExpr { - alloc := &struct { - ce CallExpr - ws [4]Word - }{} - ce := &alloc.ce - ce.Args = alloc.ws[:1] - ce.Args[0] = w - for !p.newLine { - switch p.tok { - case _EOF, semicolon, And, Or, AndExpr, OrExpr, pipeAll, - dblSemicolon, semiFall, dblSemiFall: - return ce - case _LitWord: - if litRedir(p.src, p.npos) { - p.doRedirect(s) - continue - } - ce.Args = append(ce.Args, Word{ - Parts: p.singleWps(p.lit(p.pos, p.val)), - }) - p.next() - case bckQuote: - if p.quote == subCmdBckquo { - return ce - } - fallthrough - case _Lit, dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut, - sglQuote, dollSglQuote, dblQuote, dollDblQuote, dollBrack, globQuest, - globMul, globAdd, globAt, globNot: - ce.Args = append(ce.Args, Word{Parts: p.wordParts()}) - case Gtr, Shr, Lss, dplIn, dplOut, clbOut, rdrInOut, Shl, - dashHdoc, wordHdoc, rdrAll, appAll: - p.doRedirect(s) - case rightParen: - if p.quote == subCmd { - return ce - } - fallthrough - default: - p.curErr("a command can only contain words and redirects") - } - } - return ce -} - -func (p *parser) funcDecl(name Lit, pos Pos) *FuncDecl { - fd := &FuncDecl{ - Position: pos, - BashStyle: pos != name.ValuePos, - Name: name, - } - if fd.Body, _ = p.getStmt(false); fd.Body == nil { - p.followErr(fd.Pos(), "foo()", "a statement") - } - return fd -} diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/printer.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/printer.go deleted file mode 100644 index 4141f054d..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/printer.go +++ /dev/null @@ -1,1147 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -import ( - "bufio" - "io" - "sync" -) - -// PrintConfig controls how the printing of an AST node will behave. -type PrintConfig struct { - Spaces int // 0 (default) for tabs, >0 for number of spaces -} - -var printerFree = sync.Pool{ - New: func() interface{} { - return &printer{bufWriter: bufio.NewWriter(nil)} - }, -} - -// Fprint "pretty-prints" the given AST file to the given writer. -func (c PrintConfig) Fprint(w io.Writer, f *File) error { - p := printerFree.Get().(*printer) - p.reset() - p.f, p.c = f, c - p.comments = f.Comments - p.bufWriter.Reset(w) - p.stmts(f.Stmts) - p.commentsUpTo(0) - p.newline(0) - err := p.bufWriter.Flush() - printerFree.Put(p) - return err -} - -// Fprint "pretty-prints" the given AST file to the given writer. It -// calls PrintConfig.Fprint with its default settings. -func Fprint(w io.Writer, f *File) error { - return PrintConfig{}.Fprint(w, f) -} - -type bufWriter interface { - WriteByte(byte) error - WriteString(string) (int, error) - Reset(io.Writer) - Flush() error -} - -type printer struct { - bufWriter - - f *File - c PrintConfig - - wantSpace bool - wantNewline bool - wroteSemi bool - - commentPadding int - - // nline is the position of the next newline - nline Pos - nlineIndex int - - // lastLevel is the last level of indentation that was used. - lastLevel int - // level is the current level of indentation. - level int - // levelIncs records which indentation level increments actually - // took place, to revert them once their section ends. - levelIncs []bool - - nestedBinary bool - - // comments is the list of pending comments to write. - comments []*Comment - - // pendingHdocs is the list of pending heredocs to write. - pendingHdocs []*Redirect - - // used in stmtLen to align comments - lenPrinter *printer - lenCounter byteCounter -} - -func (p *printer) reset() { - p.wantSpace, p.wantNewline = false, false - p.commentPadding = 0 - p.nline, p.nlineIndex = 0, 0 - p.lastLevel, p.level = 0, 0 - p.levelIncs = p.levelIncs[:0] - p.nestedBinary = false - p.pendingHdocs = p.pendingHdocs[:0] -} - -func (p *printer) incLine() { - if p.nlineIndex++; p.nlineIndex >= len(p.f.Lines) { - p.nline = maxPos - } else { - p.nline = Pos(p.f.Lines[p.nlineIndex]) - } -} - -func (p *printer) incLines(pos Pos) { - for p.nline < pos { - p.incLine() - } -} - -func (p *printer) space() { - p.WriteByte(' ') - p.wantSpace = false -} - -func (p *printer) spaces(n int) { - for i := 0; i < n; i++ { - p.WriteByte(' ') - } -} - -func (p *printer) tabs(n int) { - for i := 0; i < n; i++ { - p.WriteByte('\t') - } -} - -func (p *printer) bslashNewl() { - p.WriteString(" \\\n") - p.wantSpace = false - p.incLine() -} - -func (p *printer) spacedString(s string, spaceAfter bool) { - if p.wantSpace { - p.WriteByte(' ') - } - p.WriteString(s) - p.wantSpace = spaceAfter -} - -func (p *printer) semiOrNewl(s string, pos Pos) { - if p.wantNewline { - p.newline(pos) - p.indent() - } else { - if !p.wroteSemi { - p.WriteByte(';') - } - p.WriteByte(' ') - } - p.incLines(pos) - p.WriteString(s) - p.wantSpace = true -} - -func (p *printer) incLevel() { - inc := false - if p.level <= p.lastLevel { - p.level++ - inc = true - } else if last := &p.levelIncs[len(p.levelIncs)-1]; *last { - *last = false - inc = true - } - p.levelIncs = append(p.levelIncs, inc) -} - -func (p *printer) decLevel() { - if p.levelIncs[len(p.levelIncs)-1] { - p.level-- - } - p.levelIncs = p.levelIncs[:len(p.levelIncs)-1] -} - -func (p *printer) indent() { - p.lastLevel = p.level - switch { - case p.level == 0: - case p.c.Spaces == 0: - p.tabs(p.level) - case p.c.Spaces > 0: - p.spaces(p.c.Spaces * p.level) - } -} - -func (p *printer) newline(pos Pos) { - p.wantNewline, p.wantSpace = false, false - p.WriteByte('\n') - if pos > p.nline { - p.incLine() - } - hdocs := p.pendingHdocs - p.pendingHdocs = p.pendingHdocs[:0] - for _, r := range hdocs { - p.word(r.Hdoc) - p.incLines(r.Hdoc.End() + 1) - p.unquotedWord(r.Word) - p.WriteByte('\n') - p.incLine() - p.wantSpace = false - } -} - -func (p *printer) newlines(pos Pos) { - p.newline(pos) - if pos > p.nline { - // preserve single empty lines - p.WriteByte('\n') - p.incLine() - } - p.indent() -} - -func (p *printer) commentsAndSeparate(pos Pos) { - p.commentsUpTo(pos) - if p.wantNewline || pos > p.nline { - p.newlines(pos) - } -} - -func (p *printer) sepTok(s string, pos Pos) { - p.level++ - p.commentsUpTo(pos) - p.level-- - if p.wantNewline || pos > p.nline { - p.newlines(pos) - } - p.WriteString(s) - p.wantSpace = true -} - -func (p *printer) semiRsrv(s string, pos Pos, fallback bool) { - p.level++ - p.commentsUpTo(pos) - p.level-- - if p.wantNewline || pos > p.nline { - p.newlines(pos) - } else if fallback { - if !p.wroteSemi { - p.WriteByte(';') - } - p.WriteByte(' ') - } else if p.wantSpace { - p.WriteByte(' ') - } - p.WriteString(s) - p.wantSpace = true -} - -func (p *printer) commentsUpTo(pos Pos) { - if len(p.comments) < 1 { - return - } - c := p.comments[0] - if pos > 0 && c.Hash >= pos { - return - } - p.comments = p.comments[1:] - switch { - case p.nlineIndex == 0: - case c.Hash >= p.nline: - p.newlines(c.Hash) - default: - p.spaces(p.commentPadding + 1) - } - p.incLines(c.Hash) - p.WriteByte('#') - p.WriteString(c.Text) - p.commentsUpTo(pos) -} - -func (p *printer) expansionOp(op ParExpOperator) { - switch op { - case SubstAdd: - p.WriteByte('+') - case SubstColAdd: - p.WriteString(":+") - case SubstSub: - p.WriteByte('-') - case SubstColSub: - p.WriteString(":-") - case SubstQuest: - p.WriteByte('?') - case SubstColQuest: - p.WriteString(":?") - case SubstAssgn: - p.WriteByte('=') - case SubstColAssgn: - p.WriteString(":=") - case RemSmallSuffix: - p.WriteByte('%') - case RemLargeSuffix: - p.WriteString("%%") - case RemSmallPrefix: - p.WriteByte('#') - case RemLargePrefix: - p.WriteString("##") - case UpperFirst: - p.WriteByte('^') - case UpperAll: - p.WriteString("^^") - case LowerFirst: - p.WriteByte(',') - default: // LowerAll - p.WriteString(",,") - } -} - -func (p *printer) wordPart(wp WordPart) { - switch x := wp.(type) { - case *Lit: - p.WriteString(x.Value) - case *SglQuoted: - if x.Dollar { - p.WriteByte('$') - } - p.WriteByte('\'') - p.WriteString(x.Value) - p.WriteByte('\'') - p.incLines(x.End()) - case *DblQuoted: - if x.Dollar { - p.WriteByte('$') - } - p.WriteByte('"') - for i, n := range x.Parts { - p.wordPart(n) - if i == len(x.Parts)-1 { - p.incLines(n.End()) - } - } - p.WriteByte('"') - case *CmdSubst: - p.incLines(x.Pos()) - p.WriteString("$(") - p.wantSpace = len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0]) - p.nestedStmts(x.Stmts, x.Right) - p.sepTok(")", x.Right) - case *ParamExp: - if x.Short { - p.WriteByte('$') - p.WriteString(x.Param.Value) - break - } - p.WriteString("${") - if x.Length { - p.WriteByte('#') - } - p.WriteString(x.Param.Value) - if x.Ind != nil { - p.WriteByte('[') - p.word(x.Ind.Word) - p.WriteByte(']') - } - if x.Slice != nil { - p.WriteByte(':') - p.word(x.Slice.Offset) - if w2 := x.Slice.Length; w2.Parts != nil { - p.WriteByte(':') - p.word(w2) - } - } else if x.Repl != nil { - if x.Repl.All { - p.WriteByte('/') - } - p.WriteByte('/') - p.word(x.Repl.Orig) - p.WriteByte('/') - p.word(x.Repl.With) - } else if x.Exp != nil { - p.expansionOp(x.Exp.Op) - p.word(x.Exp.Word) - } - p.WriteByte('}') - case *ArithmExp: - p.WriteString("$((") - p.arithmExpr(x.X, false) - p.WriteString("))") - case *ArrayExpr: - p.wantSpace = false - p.WriteByte('(') - p.wordJoin(x.List, false) - p.sepTok(")", x.Rparen) - case *ExtGlob: - p.wantSpace = false - p.WriteString(x.Op.String()) - p.WriteString(x.Pattern.Value) - p.WriteByte(')') - case *ProcSubst: - // avoid conflict with << and others - if p.wantSpace { - p.space() - } - switch x.Op { - case CmdIn: - p.WriteString("<(") - default: // CmdOut - p.WriteString(">(") - } - p.nestedStmts(x.Stmts, 0) - p.WriteByte(')') - } - p.wantSpace = true -} - -func (p *printer) loop(loop Loop) { - switch x := loop.(type) { - case *WordIter: - p.WriteString(x.Name.Value) - if len(x.List) > 0 { - p.WriteString(" in") - p.wordJoin(x.List, true) - } - case *CStyleLoop: - p.WriteString("((") - if x.Init == nil { - p.WriteByte(' ') - } - p.arithmExpr(x.Init, false) - p.WriteString("; ") - p.arithmExpr(x.Cond, false) - p.WriteString("; ") - p.arithmExpr(x.Post, false) - p.WriteString("))") - } -} - -func (p *printer) binaryExprOp(tok Token) { - switch tok { - case Assgn: - p.WriteByte('=') - case Add: - p.WriteByte('+') - case Sub: - p.WriteByte('-') - case Rem: - p.WriteByte('%') - case Mul: - p.WriteByte('*') - case Quo: - p.WriteByte('/') - case And: - p.WriteByte('&') - case Or: - p.WriteByte('|') - case AndExpr: - p.WriteString("&&") - case OrExpr: - p.WriteString("||") - case Xor: - p.WriteByte('^') - case Pow: - p.WriteString("**") - case Eql: - p.WriteString("==") - case Neq: - p.WriteString("!=") - case Leq: - p.WriteString("<=") - case Geq: - p.WriteString(">=") - case AddAssgn: - p.WriteString("+=") - case SubAssgn: - p.WriteString("-=") - case MulAssgn: - p.WriteString("*=") - case QuoAssgn: - p.WriteString("/=") - case RemAssgn: - p.WriteString("%=") - case AndAssgn: - p.WriteString("&=") - case OrAssgn: - p.WriteString("|=") - case XorAssgn: - p.WriteString("^=") - case ShlAssgn: - p.WriteString("<<=") - case ShrAssgn: - p.WriteString(">>=") - case Lss: - p.WriteByte('<') - case Gtr: - p.WriteByte('>') - case Shl: - p.WriteString("<<") - case Shr: - p.WriteString(">>") - case Quest: - p.WriteByte('?') - case Colon: - p.WriteByte(':') - default: // Comma - p.WriteByte(',') - } -} - -func (p *printer) unaryExprOp(tok Token) { - switch tok { - case Add: - p.WriteByte('+') - case Sub: - p.WriteByte('-') - case Not: - p.WriteByte('!') - case Inc: - p.WriteString("++") - default: // Dec - p.WriteString("--") - } -} - -func (p *printer) arithmExpr(expr ArithmExpr, compact bool) { - p.wantSpace = false - switch x := expr.(type) { - case *Word: - p.word(*x) - case *BinaryArithm: - if compact { - p.arithmExpr(x.X, compact) - p.binaryExprOp(x.Op) - p.arithmExpr(x.Y, compact) - } else { - p.arithmExpr(x.X, compact) - if x.Op != Comma { - p.WriteByte(' ') - } - p.binaryExprOp(x.Op) - p.space() - p.arithmExpr(x.Y, compact) - } - case *UnaryArithm: - if x.Post { - p.arithmExpr(x.X, compact) - p.unaryExprOp(x.Op) - } else { - p.unaryExprOp(x.Op) - p.arithmExpr(x.X, compact) - } - case *ParenArithm: - p.WriteByte('(') - p.arithmExpr(x.X, false) - p.WriteByte(')') - } -} - -func (p *printer) unaryTestOp(op UnTestOperator) { - switch op { - case TsNot: - p.WriteByte('!') - case TsExists: - p.WriteString("-e") - case TsRegFile: - p.WriteString("-f") - case TsDirect: - p.WriteString("-d") - case TsCharSp: - p.WriteString("-c") - case TsBlckSp: - p.WriteString("-b") - case TsNmPipe: - p.WriteString("-p") - case TsSocket: - p.WriteString("-S") - case TsSmbLink: - p.WriteString("-L") - case TsGIDSet: - p.WriteString("-g") - case TsUIDSet: - p.WriteString("-u") - case TsRead: - p.WriteString("-r") - case TsWrite: - p.WriteString("-w") - case TsExec: - p.WriteString("-x") - case TsNoEmpty: - p.WriteString("-s") - case TsFdTerm: - p.WriteString("-t") - case TsEmpStr: - p.WriteString("-z") - case TsNempStr: - p.WriteString("-n") - case TsOptSet: - p.WriteString("-o") - case TsVarSet: - p.WriteString("-v") - default: // TsRefVar - p.WriteString("-R") - } -} - -func (p *printer) binaryTestOp(op BinTestOperator) { - switch op { - case AndTest: - p.WriteString("&&") - case OrTest: - p.WriteString("||") - case TsAssgn: - p.WriteByte('=') - case TsEqual: - p.WriteString("==") - case TsNequal: - p.WriteString("!=") - case TsReMatch: - p.WriteString("=~") - case TsNewer: - p.WriteString("-nt") - case TsOlder: - p.WriteString("-ot") - case TsDevIno: - p.WriteString("-ef") - case TsEql: - p.WriteString("-eq") - case TsNeq: - p.WriteString("-ne") - case TsLeq: - p.WriteString("-le") - case TsGeq: - p.WriteString("-ge") - case TsLss: - p.WriteString("-lt") - case TsGtr: - p.WriteString("-gt") - case TsBefore: - p.WriteByte('<') - case TsAfter: - p.WriteByte('>') - } -} - -func (p *printer) testExpr(expr TestExpr) { - p.wantSpace = false - switch x := expr.(type) { - case *Word: - p.word(*x) - case *BinaryTest: - p.testExpr(x.X) - p.space() - p.binaryTestOp(x.Op) - p.space() - p.testExpr(x.Y) - case *UnaryTest: - p.unaryTestOp(x.Op) - p.space() - p.testExpr(x.X) - case *ParenTest: - p.WriteByte('(') - p.testExpr(x.X) - p.WriteByte(')') - } -} - -func (p *printer) word(w Word) { - for _, n := range w.Parts { - p.wordPart(n) - } -} - -func (p *printer) unquotedWord(w Word) { - for _, wp := range w.Parts { - switch x := wp.(type) { - case *SglQuoted: - p.WriteString(x.Value) - case *DblQuoted: - for _, qp := range x.Parts { - p.wordPart(qp) - } - case *Lit: - if x.Value[0] == '\\' { - p.WriteString(x.Value[1:]) - } else { - p.WriteString(x.Value) - } - default: - p.wordPart(wp) - } - } -} - -func (p *printer) wordJoin(ws []Word, backslash bool) { - anyNewline := false - for _, w := range ws { - if pos := w.Pos(); pos > p.nline { - p.commentsUpTo(pos) - if backslash { - p.bslashNewl() - } else { - p.WriteByte('\n') - p.incLine() - } - if !anyNewline { - p.incLevel() - anyNewline = true - } - p.indent() - } else if p.wantSpace { - p.space() - } - for _, n := range w.Parts { - p.wordPart(n) - } - } - if anyNewline { - p.decLevel() - } -} - -func (p *printer) stmt(s *Stmt) { - if s.Negated { - p.spacedString("!", true) - } - p.assigns(s.Assigns) - startRedirs := p.command(s.Cmd, s.Redirs) - anyNewline := false - for _, r := range s.Redirs[startRedirs:] { - if r.OpPos > p.nline { - p.bslashNewl() - if !anyNewline { - p.incLevel() - anyNewline = true - } - p.indent() - } - p.commentsAndSeparate(r.OpPos) - if p.wantSpace { - p.WriteByte(' ') - } - if r.N != nil { - p.WriteString(r.N.Value) - } - p.redirectOp(r.Op) - p.wantSpace = true - p.word(r.Word) - if r.Op == Hdoc || r.Op == DashHdoc { - p.pendingHdocs = append(p.pendingHdocs, r) - } - } - p.wroteSemi = false - if s.SemiPos > 0 && s.SemiPos > p.nline { - p.incLevel() - p.bslashNewl() - p.indent() - p.decLevel() - p.WriteByte(';') - p.wroteSemi = true - } else if s.Background { - p.WriteString(" &") - } - if anyNewline { - p.decLevel() - } -} - -func (p *printer) redirectOp(op RedirOperator) { - switch op { - case RdrIn: - p.WriteByte('<') - case RdrOut: - p.WriteByte('>') - case Hdoc: - p.WriteString("<<") - case AppOut: - p.WriteString(">>") - case RdrInOut: - p.WriteString("<>") - case DplIn: - p.WriteString("<&") - case DplOut: - p.WriteString(">&") - case ClbOut: - p.WriteString(">|") - case DashHdoc: - p.WriteString("<<-") - case WordHdoc: - p.WriteString("<<<") - case RdrAll: - p.WriteString("&>") - default: // AppAll - p.WriteString("&>>") - } -} - -func binaryCmdOp(op BinCmdOperator) string { - switch op { - case AndStmt: - return "&&" - case OrStmt: - return "||" - case Pipe: - return "|" - default: // PipeAll - return "|&" - } -} - -func caseClauseOp(op CaseOperator) string { - switch op { - case DblSemicolon: - return ";;" - case SemiFall: - return ";&" - default: // DblSemiFall - return ";;&" - } -} - -func (p *printer) command(cmd Command, redirs []*Redirect) (startRedirs int) { - switch x := cmd.(type) { - case *CallExpr: - if len(x.Args) <= 1 { - p.wordJoin(x.Args, true) - return 0 - } - p.wordJoin(x.Args[:1], true) - for _, r := range redirs { - if r.Pos() > x.Args[1].Pos() || r.Op == Hdoc || r.Op == DashHdoc { - break - } - if p.wantSpace { - p.space() - } - if r.N != nil { - p.WriteString(r.N.Value) - } - p.redirectOp(r.Op) - p.wantSpace = true - p.word(r.Word) - startRedirs++ - } - p.wordJoin(x.Args[1:], true) - case *Block: - p.spacedString("{", true) - p.nestedStmts(x.Stmts, x.Rbrace) - p.semiRsrv("}", x.Rbrace, true) - case *IfClause: - p.spacedString("if", true) - p.nestedStmts(x.CondStmts, 0) - p.semiOrNewl("then", x.Then) - p.nestedStmts(x.ThenStmts, 0) - for _, el := range x.Elifs { - p.semiRsrv("elif", el.Elif, true) - p.nestedStmts(el.CondStmts, 0) - p.semiOrNewl("then", el.Then) - p.nestedStmts(el.ThenStmts, 0) - } - if len(x.ElseStmts) > 0 { - p.semiRsrv("else", x.Else, true) - p.nestedStmts(x.ElseStmts, 0) - } else if x.Else > 0 { - p.incLines(x.Else) - } - p.semiRsrv("fi", x.Fi, true) - case *Subshell: - p.spacedString("(", false) - p.wantSpace = len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0]) - p.nestedStmts(x.Stmts, x.Rparen) - p.sepTok(")", x.Rparen) - case *WhileClause: - p.spacedString("while", true) - p.nestedStmts(x.CondStmts, 0) - p.semiOrNewl("do", x.Do) - p.nestedStmts(x.DoStmts, 0) - p.semiRsrv("done", x.Done, true) - case *ForClause: - p.spacedString("for ", true) - p.loop(x.Loop) - p.semiOrNewl("do", x.Do) - p.nestedStmts(x.DoStmts, 0) - p.semiRsrv("done", x.Done, true) - case *BinaryCmd: - p.stmt(x.X) - indent := !p.nestedBinary - if indent { - p.incLevel() - } - _, p.nestedBinary = x.Y.Cmd.(*BinaryCmd) - if len(p.pendingHdocs) == 0 && x.Y.Pos() > p.nline { - p.bslashNewl() - p.indent() - } - p.spacedString(binaryCmdOp(x.Op), true) - p.incLines(x.Y.Pos()) - p.stmt(x.Y) - if indent { - p.decLevel() - } - p.nestedBinary = false - case *FuncDecl: - if x.BashStyle { - p.WriteString("function ") - } - p.WriteString(x.Name.Value) - p.WriteString("() ") - p.incLines(x.Body.Pos()) - p.stmt(x.Body) - case *CaseClause: - p.spacedString("case ", true) - p.word(x.Word) - p.WriteString(" in") - p.incLevel() - for _, pl := range x.List { - p.commentsAndSeparate(pl.Patterns[0].Pos()) - for i, w := range pl.Patterns { - if i > 0 { - p.spacedString("|", true) - } - if p.wantSpace { - p.WriteByte(' ') - } - for _, n := range w.Parts { - p.wordPart(n) - } - } - p.WriteByte(')') - sep := len(pl.Stmts) > 1 || (len(pl.Stmts) > 0 && pl.Stmts[0].Pos() > p.nline) - p.nestedStmts(pl.Stmts, 0) - p.level++ - if sep { - p.sepTok(caseClauseOp(pl.Op), pl.OpPos) - } else { - p.spacedString(caseClauseOp(pl.Op), true) - } - p.incLines(pl.OpPos) - p.level-- - if sep || pl.OpPos == x.Esac { - p.wantNewline = true - } - } - p.decLevel() - p.semiRsrv("esac", x.Esac, len(x.List) == 0) - case *UntilClause: - p.spacedString("until", true) - p.nestedStmts(x.CondStmts, 0) - p.semiOrNewl("do", x.Do) - p.nestedStmts(x.DoStmts, 0) - p.semiRsrv("done", x.Done, true) - case *ArithmCmd: - if p.wantSpace { - p.space() - } - p.WriteString("((") - p.arithmExpr(x.X, false) - p.WriteString("))") - case *TestClause: - p.spacedString("[[", true) - p.space() - p.testExpr(x.X) - p.spacedString("]]", true) - case *DeclClause: - name := x.Variant - if name == "" { - name = "declare" - } - p.spacedString(name, true) - for _, w := range x.Opts { - p.WriteByte(' ') - p.word(w) - } - p.assigns(x.Assigns) - case *EvalClause: - p.spacedString("eval", true) - if x.Stmt != nil { - p.stmt(x.Stmt) - } - case *CoprocClause: - p.spacedString("coproc", true) - if x.Name != nil { - p.WriteByte(' ') - p.WriteString(x.Name.Value) - } - p.stmt(x.Stmt) - case *LetClause: - p.spacedString("let", true) - for _, n := range x.Exprs { - p.space() - p.arithmExpr(n, true) - } - } - return startRedirs -} - -func startsWithLparen(s *Stmt) bool { - switch x := s.Cmd.(type) { - case *Subshell: - return true - case *BinaryCmd: - return startsWithLparen(x.X) - } - return false -} - -func (p *printer) hasInline(pos, npos, nline Pos) bool { - for _, c := range p.comments { - if c.Hash > nline { - return false - } - if c.Hash > pos && (npos == 0 || c.Hash < npos) { - return true - } - } - return false -} - -func (p *printer) stmts(stmts []*Stmt) { - switch len(stmts) { - case 0: - return - case 1: - s := stmts[0] - pos := s.Pos() - p.commentsUpTo(pos) - if pos <= p.nline { - p.stmt(s) - } else { - if p.nlineIndex > 0 { - p.newlines(pos) - } else { - p.incLines(pos) - } - p.stmt(s) - p.wantNewline = true - } - return - } - inlineIndent := 0 - for i, s := range stmts { - pos := s.Pos() - ind := p.nlineIndex - p.commentsUpTo(pos) - if p.nlineIndex > 0 { - p.newlines(pos) - } - p.incLines(pos) - p.stmt(s) - var npos Pos - if i+1 < len(stmts) { - npos = stmts[i+1].Pos() - } - if !p.hasInline(pos, npos, p.nline) { - inlineIndent = 0 - p.commentPadding = 0 - continue - } - if ind < len(p.f.Lines)-1 && s.End() > Pos(p.f.Lines[ind+1]) { - inlineIndent = 0 - } - if inlineIndent == 0 { - ind2 := p.nlineIndex - nline2 := p.nline - follow := stmts[i:] - for j, s2 := range follow { - pos2 := s2.Pos() - var npos2 Pos - if j+1 < len(follow) { - npos2 = follow[j+1].Pos() - } - if pos2 > nline2 || !p.hasInline(pos2, npos2, nline2) { - break - } - if l := p.stmtLen(s2); l > inlineIndent { - inlineIndent = l - } - if ind2++; ind2 >= len(p.f.Lines) { - nline2 = maxPos - } else { - nline2 = Pos(p.f.Lines[ind2]) - } - } - if ind2 == p.nlineIndex+1 { - // no inline comments directly after this one - continue - } - } - if inlineIndent > 0 { - p.commentPadding = inlineIndent - p.stmtLen(s) - } - } - p.wantNewline = true -} - -type byteCounter int - -func (c *byteCounter) WriteByte(b byte) error { - *c++ - return nil -} -func (c *byteCounter) WriteString(s string) (int, error) { - *c += byteCounter(len(s)) - return 0, nil -} -func (c *byteCounter) Reset(io.Writer) { *c = 0 } -func (c *byteCounter) Flush() error { return nil } - -func (p *printer) stmtLen(s *Stmt) int { - if p.lenPrinter == nil { - p.lenPrinter = new(printer) - } - *p.lenPrinter = printer{bufWriter: &p.lenCounter} - p.lenPrinter.bufWriter.Reset(nil) - p.lenPrinter.f = p.f - p.lenPrinter.incLines(s.Pos()) - p.lenPrinter.stmt(s) - return int(p.lenCounter) -} - -func (p *printer) nestedStmts(stmts []*Stmt, closing Pos) { - p.incLevel() - if len(stmts) == 1 && closing > p.nline && stmts[0].End() <= p.nline { - p.newline(0) - p.indent() - } - p.stmts(stmts) - p.decLevel() -} - -func (p *printer) assigns(assigns []*Assign) { - anyNewline := false - for _, a := range assigns { - if a.Pos() > p.nline { - p.bslashNewl() - if !anyNewline { - p.incLevel() - anyNewline = true - } - p.indent() - } else if p.wantSpace { - p.space() - } - if a.Name != nil { - p.WriteString(a.Name.Value) - if a.Append { - p.WriteByte('+') - } - p.WriteByte('=') - } - p.word(a.Value) - p.wantSpace = true - } - if anyNewline { - p.decLevel() - } -} diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/tokens.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/tokens.go deleted file mode 100644 index dee108a25..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/tokens.go +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -// Token is the set of lexical tokens and reserved words. -type Token int - -// The list of all possible tokens and reserved words. -const ( - illegalTok Token = iota - _EOF - _Lit - _LitWord - - sglQuote // ' - dblQuote // " - bckQuote // ` - - And // & - AndExpr // && - OrExpr // || - Or // | - pipeAll // |& - bash - - dollar // $ - dollSglQuote // $' - bash - dollDblQuote // $" - bash - dollBrace // ${ - dollBrack // $[ - dollParen // $( - dollDblParen // $(( - leftBrack // [ - leftParen // ( - dblLeftParen // (( - bash - - rightBrace // } - rightBrack // ] - rightParen // ) - dblRightParen // )) - semicolon // ; - - dblSemicolon // ;; - semiFall // ;& - bash - dblSemiFall // ;;& - bash - - Mul // * - Not // ! - Inc // ++ - Dec // -- - Pow // ** - Eql // == - Neq // != - Leq // <= - Geq // >= - - AddAssgn // += - SubAssgn // -= - MulAssgn // *= - QuoAssgn // /= - RemAssgn // %= - AndAssgn // &= - OrAssgn // |= - XorAssgn // ^= - ShlAssgn // <<= - ShrAssgn // >>= - - Gtr // > - Shr // >> - Lss // < - rdrInOut // <> - dplIn // <& - dplOut // >& - clbOut // >| - Shl // << - dashHdoc // <<- - wordHdoc // <<< - bash - rdrAll // &> - bash - appAll // &>> - bash - - cmdIn // <( - bash - cmdOut // >( - bash - - Add // + - ColAdd // :+ - Sub // - - ColSub // :- - Quest // ? - ColQuest // :? - Assgn // = - ColAssgn // := - Rem // % - dblRem // %% - Hash // # - dblHash // ## - Xor // ^ - dblXor // ^^ - bash - Comma // , - dblComma // ,, - bash - Quo // / - dblQuo // // - Colon // : - - tsNot // ! - tsExists // -e - tsRegFile // -f - tsDirect // -d - tsCharSp // -c - tsBlckSp // -b - tsNmPipe // -p - tsSocket // -S - tsSmbLink // -L - tsGIDSet // -g - tsUIDSet // -u - tsRead // -r - tsWrite // -w - tsExec // -x - tsNoEmpty // -s - tsFdTerm // -t - tsEmpStr // -z - tsNempStr // -n - tsOptSet // -o - tsVarSet // -v - tsRefVar // -R - - tsReMatch // =~ - tsNewer // -nt - tsOlder // -ot - tsDevIno // -ef - tsEql // -eq - tsNeq // -ne - tsLeq // -le - tsGeq // -ge - tsLss // -lt - tsGtr // -gt - - globQuest // ?( - globMul // *( - globAdd // +( - globAt // @( - globNot // !( -) - -type RedirOperator Token - -const ( - RdrOut = RedirOperator(Gtr) + iota - AppOut - RdrIn - RdrInOut - DplIn - DplOut - ClbOut - Hdoc - DashHdoc - WordHdoc - RdrAll - AppAll -) - -type ProcOperator Token - -const ( - CmdIn = ProcOperator(cmdIn) + iota - CmdOut -) - -type GlobOperator Token - -const ( - GlobQuest = GlobOperator(globQuest) + iota - GlobMul - GlobAdd - GlobAt - GlobNot -) - -type BinCmdOperator Token - -const ( - AndStmt = BinCmdOperator(AndExpr) + iota - OrStmt - Pipe - PipeAll -) - -type CaseOperator Token - -const ( - DblSemicolon = CaseOperator(dblSemicolon) + iota - SemiFall - DblSemiFall -) - -type ParExpOperator Token - -const ( - SubstAdd = ParExpOperator(Add) + iota - SubstColAdd - SubstSub - SubstColSub - SubstQuest - SubstColQuest - SubstAssgn - SubstColAssgn - RemSmallSuffix - RemLargeSuffix - RemSmallPrefix - RemLargePrefix - UpperFirst - UpperAll - LowerFirst - LowerAll -) - -type UnTestOperator Token - -const ( - TsNot = UnTestOperator(tsNot) + iota - TsExists - TsRegFile - TsDirect - TsCharSp - TsBlckSp - TsNmPipe - TsSocket - TsSmbLink - TsGIDSet - TsUIDSet - TsRead - TsWrite - TsExec - TsNoEmpty - TsFdTerm - TsEmpStr - TsNempStr - TsOptSet - TsVarSet - TsRefVar -) - -type BinTestOperator Token - -const ( - TsReMatch = BinTestOperator(tsReMatch) + iota - TsNewer - TsOlder - TsDevIno - TsEql - TsNeq - TsLeq - TsGeq - TsLss - TsGtr - AndTest = BinTestOperator(AndExpr) - OrTest = BinTestOperator(OrExpr) - TsAssgn = BinTestOperator(Assgn) - TsEqual = BinTestOperator(Eql) - TsNequal = BinTestOperator(Neq) - TsBefore = BinTestOperator(Lss) - TsAfter = BinTestOperator(Gtr) -) - -func (o RedirOperator) String() string { return Token(o).String() } -func (o ProcOperator) String() string { return Token(o).String() } -func (o GlobOperator) String() string { return Token(o).String() } -func (o BinCmdOperator) String() string { return Token(o).String() } -func (o CaseOperator) String() string { return Token(o).String() } -func (o ParExpOperator) String() string { return Token(o).String() } -func (o UnTestOperator) String() string { return Token(o).String() } -func (o BinTestOperator) String() string { return Token(o).String() } - -// Pos is the internal representation of a position within a source -// file. -type Pos int - -var defaultPos Pos - -const maxPos = Pos(^uint(0) >> 1) - -// Position describes a position within a source file including the line -// and column location. A Position is valid if the line number is > 0. -type Position struct { - Offset int // byte offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (in bytes) -} - -var tokNames = map[Token]string{ - illegalTok: "illegal", - _EOF: "EOF", - _Lit: "Lit", - _LitWord: "LitWord", - - sglQuote: "'", - dblQuote: `"`, - bckQuote: "`", - - And: "&", - AndExpr: "&&", - OrExpr: "||", - Or: "|", - pipeAll: "|&", - - dollar: "$", - dollSglQuote: "$'", - dollDblQuote: `$"`, - dollBrace: "${", - dollBrack: "$[", - dollParen: "$(", - dollDblParen: "$((", - leftBrack: "[", - leftParen: "(", - dblLeftParen: "((", - - rightBrace: "}", - rightBrack: "]", - rightParen: ")", - dblRightParen: "))", - semicolon: ";", - - dblSemicolon: ";;", - semiFall: ";&", - dblSemiFall: ";;&", - - Gtr: ">", - Shr: ">>", - Lss: "<", - rdrInOut: "<>", - dplIn: "<&", - dplOut: ">&", - clbOut: ">|", - Shl: "<<", - dashHdoc: "<<-", - wordHdoc: "<<<", - rdrAll: "&>", - appAll: "&>>", - - cmdIn: "<(", - cmdOut: ">(", - - Add: "+", - ColAdd: ":+", - Sub: "-", - ColSub: ":-", - Quest: "?", - ColQuest: ":?", - Assgn: "=", - ColAssgn: ":=", - Rem: "%", - dblRem: "%%", - Hash: "#", - dblHash: "##", - Xor: "^", - dblXor: "^^", - Comma: ",", - dblComma: ",,", - Quo: "/", - dblQuo: "//", - Colon: ":", - - Mul: "*", - Not: "!", - Inc: "++", - Dec: "--", - Pow: "**", - Eql: "==", - Neq: "!=", - Leq: "<=", - Geq: ">=", - - AddAssgn: "+=", - SubAssgn: "-=", - MulAssgn: "*=", - QuoAssgn: "/=", - RemAssgn: "%=", - AndAssgn: "&=", - OrAssgn: "|=", - XorAssgn: "^=", - ShlAssgn: "<<=", - ShrAssgn: ">>=", - - tsNot: "!", - tsExists: "-e", - tsRegFile: "-f", - tsDirect: "-d", - tsCharSp: "-c", - tsBlckSp: "-b", - tsNmPipe: "-p", - tsSocket: "-S", - tsSmbLink: "-L", - tsGIDSet: "-g", - tsUIDSet: "-u", - tsRead: "-r", - tsWrite: "-w", - tsExec: "-x", - tsNoEmpty: "-s", - tsFdTerm: "-t", - tsEmpStr: "-z", - tsNempStr: "-n", - tsOptSet: "-o", - tsVarSet: "-v", - tsRefVar: "-R", - - tsReMatch: "=~", - tsNewer: "-nt", - tsOlder: "-ot", - tsDevIno: "-ef", - tsEql: "-eq", - tsNeq: "-ne", - tsLeq: "-le", - tsGeq: "-ge", - tsLss: "-lt", - tsGtr: "-gt", - - globQuest: "?(", - globMul: "*(", - globAdd: "+(", - globAt: "@(", - globNot: "!(", -} - -func (t Token) String() string { return tokNames[t] } diff --git a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/walk.go b/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/walk.go deleted file mode 100644 index 76d333908..000000000 --- a/vendor/github.com/weaveworks/common/tools/vendor/github.com/mvdan/sh/syntax/walk.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2016, Daniel Martí -// See LICENSE for licensing information - -package syntax - -import "fmt" - -// Visitor holds a Visit method which is invoked for each node -// encountered by Walk. If the result visitor w is not nil, Walk visits -// each of the children of node with the visitor w, followed by a call -// of w.Visit(nil). -type Visitor interface { - Visit(node Node) (w Visitor) -} - -func walkStmts(v Visitor, stmts []*Stmt) { - for _, s := range stmts { - Walk(v, s) - } -} - -func walkWords(v Visitor, words []Word) { - for i := range words { - Walk(v, &words[i]) - } -} - -// Walk traverses an AST in depth-first order: It starts by calling -// v.Visit(node); node must not be nil. If the visitor w returned by -// v.Visit(node) is not nil, Walk is invoked recursively with visitor w -// for each of the non-nil children of node, followed by a call of -// w.Visit(nil). -func Walk(v Visitor, node Node) { - if v = v.Visit(node); v == nil { - return - } - - switch x := node.(type) { - case *File: - walkStmts(v, x.Stmts) - case *Stmt: - if x.Cmd != nil { - Walk(v, x.Cmd) - } - for _, a := range x.Assigns { - Walk(v, a) - } - for _, r := range x.Redirs { - Walk(v, r) - } - case *Assign: - if x.Name != nil { - Walk(v, x.Name) - } - Walk(v, &x.Value) - case *Redirect: - if x.N != nil { - Walk(v, x.N) - } - Walk(v, &x.Word) - if len(x.Hdoc.Parts) > 0 { - Walk(v, &x.Hdoc) - } - case *CallExpr: - walkWords(v, x.Args) - case *Subshell: - walkStmts(v, x.Stmts) - case *Block: - walkStmts(v, x.Stmts) - case *IfClause: - walkStmts(v, x.CondStmts) - walkStmts(v, x.ThenStmts) - for _, elif := range x.Elifs { - walkStmts(v, elif.CondStmts) - walkStmts(v, elif.ThenStmts) - } - walkStmts(v, x.ElseStmts) - case *WhileClause: - walkStmts(v, x.CondStmts) - walkStmts(v, x.DoStmts) - case *UntilClause: - walkStmts(v, x.CondStmts) - walkStmts(v, x.DoStmts) - case *ForClause: - Walk(v, x.Loop) - walkStmts(v, x.DoStmts) - case *WordIter: - Walk(v, &x.Name) - walkWords(v, x.List) - case *CStyleLoop: - if x.Init != nil { - Walk(v, x.Init) - } - if x.Cond != nil { - Walk(v, x.Cond) - } - if x.Post != nil { - Walk(v, x.Post) - } - case *BinaryCmd: - Walk(v, x.X) - Walk(v, x.Y) - case *FuncDecl: - Walk(v, &x.Name) - Walk(v, x.Body) - case *Word: - for _, wp := range x.Parts { - Walk(v, wp) - } - case *Lit: - case *SglQuoted: - case *DblQuoted: - for _, wp := range x.Parts { - Walk(v, wp) - } - case *CmdSubst: - walkStmts(v, x.Stmts) - case *ParamExp: - Walk(v, &x.Param) - if x.Ind != nil { - Walk(v, &x.Ind.Word) - } - if x.Repl != nil { - Walk(v, &x.Repl.Orig) - Walk(v, &x.Repl.With) - } - if x.Exp != nil { - Walk(v, &x.Exp.Word) - } - case *ArithmExp: - if x.X != nil { - Walk(v, x.X) - } - case *ArithmCmd: - if x.X != nil { - Walk(v, x.X) - } - case *BinaryArithm: - Walk(v, x.X) - Walk(v, x.Y) - case *BinaryTest: - Walk(v, x.X) - Walk(v, x.Y) - case *UnaryArithm: - Walk(v, x.X) - case *UnaryTest: - Walk(v, x.X) - case *ParenArithm: - Walk(v, x.X) - case *ParenTest: - Walk(v, x.X) - case *CaseClause: - Walk(v, &x.Word) - for _, pl := range x.List { - walkWords(v, pl.Patterns) - walkStmts(v, pl.Stmts) - } - case *TestClause: - Walk(v, x.X) - case *DeclClause: - walkWords(v, x.Opts) - for _, a := range x.Assigns { - Walk(v, a) - } - case *ArrayExpr: - walkWords(v, x.List) - case *ExtGlob: - Walk(v, &x.Pattern) - case *ProcSubst: - walkStmts(v, x.Stmts) - case *EvalClause: - if x.Stmt != nil { - Walk(v, x.Stmt) - } - case *CoprocClause: - if x.Name != nil { - Walk(v, x.Name) - } - Walk(v, x.Stmt) - case *LetClause: - for _, expr := range x.Exprs { - Walk(v, expr) - } - default: - panic(fmt.Sprintf("ast.Walk: unexpected node type %T", x)) - } - - v.Visit(nil) -} diff --git a/vendor/github.com/weaveworks/common/user/id.go b/vendor/github.com/weaveworks/common/user/id.go new file mode 100644 index 000000000..4b90a2a55 --- /dev/null +++ b/vendor/github.com/weaveworks/common/user/id.go @@ -0,0 +1,32 @@ +package user + +import ( + "fmt" + + "golang.org/x/net/context" +) + +// UserIDContextKey is the key used in contexts to find the userid +type contextKey int + +const userIDContextKey contextKey = 0 + +// OrgIDHeaderName is a legacy from scope as a service. +const OrgIDHeaderName = "X-Scope-OrgID" + +// LowerOrgIDHeaderName as gRPC / HTTP2.0 headers are lowercased. +const LowerOrgIDHeaderName = "x-scope-orgid" + +// GetID returns the user +func GetID(ctx context.Context) (string, error) { + userid, ok := ctx.Value(userIDContextKey).(string) + if !ok { + return "", fmt.Errorf("no user id") + } + return userid, nil +} + +// WithID returns a derived context containing the user ID. +func WithID(ctx context.Context, userID string) context.Context { + return context.WithValue(ctx, interface{}(userIDContextKey), userID) +} diff --git a/vendor/manifest b/vendor/manifest index 7b3bf7510..976666e7c 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -1361,7 +1361,7 @@ "importpath": "github.com/weaveworks/common", "repository": "https://github.com/weaveworks/common", "vcs": "git", - "revision": "139d0313ac15170e9de8187b26e7df03b4cb910e", + "revision": "8da456c848efd2a13ffb5a3f9f4507c52c3f52e1", "branch": "master", "notests": true },